代码随想录第4天

代码随想录训练营第4天,链表也要收尾啦。

24. 两两交换链表中的节点

题目描述:
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

解法一:设置虚拟头节点

基本思路:建议画图

  1. 首先设置虚拟头结点 dummyHead,并将其指向原本的头结点,且为当前节点 cur
    进入循环,终止条件为头结点后面不存在两个节点
  2. 通过改变指针的方向来交换头结点后面两个点node1,node2的位置
  • cur.next = node2
  • node2.next = node1;
  • node1.next = node2.next;
  1. 更新 cur 的位置,往后移一位
class Solution {
    public ListNode swapPairs(ListNode head) {
        //创建虚拟头节点,将虚拟头节点设成当前节点cur
        ListNode dummyHead = new ListNode(0);
        dummyHead.next = head;
        ListNode cur = dummyHead; 
        while(cur.next != null && cur.next.next != null){
            ListNode node1 = cur.next;
            ListNode node2 = cur.next.next;
            //三部曲,注意顺序
            cur.next = node2;
            node1.next = node2.next;
            node2.next = node1;
            cur = node1;
        }
        return dummyHead.next;
    }
}

解法二:迭代法 (稍后更新)

19.删除链表的倒数第N个节点

题目描述:
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
进阶:你能尝试使用一趟扫描实现吗?

解法一:快慢指针+虚拟头节点

主旨:设置快慢指针,想让快指针走n步,然后让快慢指针同时走,等快指针指向null的时候,删除慢指针所指的点;
1.设置虚拟头,初始化快慢指针,都指向虚拟头
2.快指针走/n+1/步,为的是让慢指针指向要删的前一个节点,方便链表操作
3.快慢指针同时走,快指针指向null时停
4.慢指针删除它目前位置的下一个节点
5.返回头节点

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        //初始设置,双指针法
        ListNode dummyHead = new ListNode(0);
        dummyHead.next = head;
        ListNode fast = dummyHead;
        ListNode slow = dummyHead;
        //先让fast指针跑n个位置
        for(int i=0; i<n;i++){
            fast = fast.next;
        }
        //当fast 在n 位上时,slow 和 fast 同时往前,直到fast走到底        
        while(fast.next != null){
           fast = fast.next;
           slow = slow.next; 
        }
        slow.next = slow.next.next;
        return dummyHead.next;
    }
}

面试题 02.07. 链表相交

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null。

解法一:常规解法

基本思路:
找出两个链表交点的指针;比较指针,不是比较值
题目为了方便比较,默认数值相同则指针就相同!
1.设置currA,currB两指针,分别指向两个链表的表头;
2.计算A,B长度;将长的链表设为A,并且移动currA到B表头的位置;让currA和currB处于同一起跑线
3.currA,currB同时移动,如果指针相同,则返回currA;没有则返回null。

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        //初始化
        ListNode currA = headA;
        ListNode currB = headB;
        int lenA = 0;
        int lenB = 0;
        //计算两个链表的长度
        while(currA != null){
            lenA++;
            currA = currA.next;
        }
        while(currB != null){
            lenB++;
            currB = currB.next;
        }
        //将当前节点重新初始化头节点
        currA = headA;
        currB = headB;
        //确保A链表是长的那个
        if(lenB > lenA){
            int tempL = lenB;
            lenB = lenA;
            lenA = tempL;
            ListNode tempN = currB;
            currB = currA;
            currA = tempN;
        }
         int gap = lenA - lenB;
        //当链表A被遍历到和B链表一样的位置时,currA 和 currB 齐头并进
         for (int i = 0; i < gap;i++){
             currA = currA.next;
         }
         while(currA != null){
             if (currA == currB){
                 return currA;
             }
             currA = currA.next;
             currB = currB.next;
         }
         return null;
    }
}

解法二:高级解法

解题思路:把两条链表相加,成为一条长的链表
headA先遍历表A再去遍历表B;
headB先遍历表B再去遍历表A;
当A,B重合时:
·如果有公共节点,则停在公共节点上;
·如果没有公共节点,两点只会都停在null上
因此,返回A即可;

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode A = headA;
        ListNode B = headB;
        while(A != B){
            A = A != null ? A.next : headB;
            B = B != null ? B.next : headA;
        }
        return A;
    }
}

142.环形链表II

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。

解法一:快慢指针

基本思路:

  1. 设置 fast 和 slow 两个指针,开始遍历链表;初始化都在 head 节点。
  2. fast 每次走两步,slow 每次走一步,如果存在环,则 fast 和 slow 必定在环内相遇;如果不存在环,则返回 null
  3. 当 fast 和 slow 相遇时,将 index1 设为 fast 的位置,将 index2 设为 head 的位置;每次 index1 和 index2 都走一步,最终 index1 和 index2 会在环入口相遇。则返回 index1.
    具体证明过程,见https://programmercarl.com/0142.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8II.html#%E6%80%9D%E8%B7%AF
public class Solution {
    public ListNode detectCycle(ListNode head) {
        // if (head == null || head.next == null){
        //     return null;
        // }
        ListNode slow = head;
        ListNode fast = head;
        while(fast != null && fast.next != null){
            slow = slow.next;
            fast = fast.next.next;
            if (fast == slow){
                ListNode index1 = fast;
                ListNode index2 = head;
                while(index1 != index2){
                    index1 = index1.next;
                    index2 = index2.next;
                }
                return index1;
            }
        }
        return null;
    }
}

解法二:哈希表(稍后更新)

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容