算法练习---反转链表

90 阅读3分钟

1反转整个链表

1.1题目详情

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

1.2递归

  class Solution {
    public ListNode reverseList(ListNode head) {
       
       //递归终止条件
       if(head==null||head.next==null) return head;

       //进入递归,最后返回最后一个节点,即为反转后的头节点
       ListNode newHead=reverseList(head.next);

       //当前节点的下一个节点的下一个节点指向当前节点
       head.next.next=head;
       head.next=null;

       return newHead;

       
    }
}

1.3迭代

class Solution {
    public ListNode reverseList(ListNode head) {
       
       if(head==null||head.next==null) return head;

       ListNode prev=null;
       ListNode next=null;
       ListNode curr=head;

       while(curr!=null){
           next=curr.next;
           curr.next=prev;
           prev=curr;
           curr=next;

       }

       return prev;
    }
}

1.4递归和迭代总结

1.4.1递归,就是在运行的过程中调用自己。
 构成递归需具备的条件:
     1. 子问题须与原始问题为同样的事,且更为简单;
     2. 不能无限制地调用本身,须有个出口,化简为非递归状况处理。
1.4.2 迭代法也称辗转法,是一种不断用变量的旧值递推新值的过程,跟迭代法相对应的是直接法(或者称为一次解法),即一次性解决问题。
1.4.3递归中一定有迭代,但是迭代中不一定有递归,大部分可以相互转换.能用迭代的不用递归,

2反转链表指定区间的节点

2.1题目详情

给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。

2.2递归

class Solution {
	//保存第n+1个节点,因为反转之后原头节点的下一个节点变为第n+1个节点
    ListNode node=null;
    //反转前n个节点
    public ListNode reverseN(ListNode head,int n){
        if(n==1){
            node=head.next;
            return head;
        }

        ListNode last=reverseN(head.next,n-1);

        head.next.next=head;
        head.next=node;

        return last;

    }
    public ListNode reverseBetween(ListNode head, int left, int right) {
        if(left==1){
        	//相当于反转前right个节点
            return reverseN(head,right);
        }else{
            head.next=reverseBetween(head.next,left-1,right-1);
            return head;
        }
    }
}

2.3迭代

class Solution {
    public ListNode reverseBetween(ListNode head, int left, int right) {
        ListNode pre=null;
        ListNode beginNode=null;
        ListNode endNode=null;
        ListNode temp=head;
        int count=1;
        while(temp!=null){
            if(left-1==count){
                beginNode=temp;
            }
            if(right+1==count){
                endNode=temp;
                break;
            }
            temp=temp.next;
            count++;
        }
       
        ListNode prev=endNode;
        ListNode next=null;
        //beginNode==null说明left=1,即开始反转的节点为头节点
        ListNode curr=beginNode==null?head:beginNode.next;

        while(curr!=endNode){
            next=curr.next;
            curr.next=prev;
            prev=curr;
            curr=next;

        }

        if(beginNode==null) return prev;

        beginNode.next=prev;

        return head;

    }
}

3k个一组反转链表

3.1题目详情给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。

k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

3.2递归加迭代

class Solution {
	//反转[start,end)
    public ListNode reverse(ListNode start,ListNode end){
        ListNode prev=end;
        ListNode next=null;
        ListNode curr=start;

        while(curr!=end){
            next=curr.next;
            curr.next=prev;
            prev=curr;
            curr=next;
        }

        return prev;
    }
    public ListNode reverseKGroup(ListNode head, int k) {

        ListNode startNode=head;
        ListNode endNode=head;
        for(int i=0;i<k;i++){
           //节点总数小于k,不进行反转,直接返回start节点
           if(endNode==null) return startNode;
           endNode=endNode.next;
        }
		//反转后的节点成为新的头节点
        ListNode newHead=reverse(startNode,endNode);
        //原头节点的下一个节点为下一次反转后的头节点
        startNode.next=reverseKGroup(endNode,k);
        return newHead; 
    }
}