【面试经典】反转链表——如何在链表中穿针引线

反转整个链表(简单)

很简单且经典的题目。就是将 1->2->3->4->5 反转为 5->4->3->2->1

有两种思路,迭代递归。先看图再看代码:

在这里插入图片描述

1)迭代——经典的双/三指针

class Solution {
    
    
    public ListNode reverseList(ListNode head) {
    
    
        ListNode pre = null;
        ListNode cur = head;
        while (cur != null) {
    
    
            ListNode nxt = cur.next;
            cur.next = pre;
            pre = cur;
            cur = nxt;
        }
        return pre;
    }
}

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)遍历到哪个节点,就将哪个节点提前到第一个;

2)这个过程需要借助dummy虚节点;

3)移动的双指针为cur和nxt(每次取cur的下一个为nxt;由于nxt不断提前,cur不断自动后移)

dummy -> 1 -> 2 -> 3 -> 4 -> 5		提前2
dummy -> 2 -> 1 -> 3 -> 4 -> 5		提前3
dummy -> 3 -> 2 -> 1 -> 4 -> 5		提前4
dummy -> 4 -> 3 -> 2 -> 1 -> 5		提前5
dummy -> 5 -> 4 -> 3 -> 2 -> 1		大功告成!
class Solution {
    
    
	public ListNode reverseList3(ListNode head) {
    
    
        if (head == null) {
    
    
            return null;
        }
        ListNode dummy = new ListNode(-1, head);
        ListNode pre = dummy;
        ListNode cur = head;
        ListNode nxt = null;
        while (cur.next != null) {
    
    
            nxt = cur.next;
            cur.next = nxt.next;
            nxt.next = pre.next;
            pre.next = nxt;
        }
        return dummy.next;
    }
}

 
 

反转部分链表(难点)

学会了迭代和递归就够了,为什么还要学习第三种“提前”法?正是为此题做准备:

在这里插入图片描述

如果使用迭代/递归,算法和实现和边界的处理都非常麻烦:

1)遍历一次,找到left和right的位置及其哨兵的位置;

2)截取链表,用迭代/递归进行反转,同时还要有头/尾的指针;

3)拼接回去;

而如果使用第三种方法,也就一次遍历的事儿:

1)for(left)找到pre的位置并固定;

2)for(right-left)对要反转的部分节点不断进行提前的操作;

3)结束;

在这里插入图片描述

class Solution {
    
    
    public ListNode reverseBetween(ListNode head, int left, int right) {
    
    
        ListNode dummy = new ListNode(-1);
        dummy.next = head;
        ListNode pre = dummy;
        ListNode cur = null;
        ListNode nxt = null;
        for (int i = 0; i < left - 1; i++) {
    
    
            pre = pre.next;
        }
        cur = pre.next;
        for (int i = 0; i < right - left; i++) {
    
    
        	// 这段取“nxt然后提前”的代码,像是在链表上穿针引线 >_<
            nxt = cur.next;
            cur.next = nxt.next;
            nxt.next = pre.next;
            pre.next = nxt;
        }
        return dummy.next;
    }
}

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

E N D END END

猜你喜欢

转载自blog.csdn.net/m0_46202073/article/details/114978040