代码随想录day04| 24. 两两交换链表中的节点、19. 删除链表的倒数第 N 个结点、面试题 02.07. 链表相交、142. 环形链表 II

目录

24  两两交换链表中的节点

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

面试题 02.07  链表相交、142. 环形链表 II

142  环形链表 II


24  两两交换链表中的节点

题目链接

看到题目的第一想法:看到题目之后,发现是链表两两交换,总在考虑元素数量是奇数还是偶数的问题,并没有清晰的解题思路。

看完代码随想录之后的想法:卡哥的方法,一步一步实现,元素从0开始,首先保存第2个元素的值temp,而后dummynode(最开始为-1)指向第1个元素,而第1个元素指向第0个元素,最后第0个元素指向temp;而后pre与head各步进一位,即pre = head(此时为第1个元素),head = head.next(此时为第2个元素),相当于pre,head从-1,0变成了1,2;最后返回了dummynode.next;

代码实现:

class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dummy = new ListNode(-1);
        dummy.next = head;
        ListNode pre = dummy;
        while (pre.next != null && pre.next.next != null) {
            //临时指针存放head.next.next
            ListNode temp = head.next.next;
            //pre指向head.next
            pre.next = head.next;
            //head.next的下一个(即head.next.next)是head
            head.next.next = head;
            //head指向temp
            head.next = temp;
            //pre与head各步进一位
            pre = head;
            head = head.next;
        }
        return dummy.next;
    }
}

实现过程中遇到哪些困难:

  • 在head.next元素要指向head的时候,总是误以为要写成head.next = head,正确的写法应当为head.next.next = head!
  • pre与head在各需要步进的时候,只步进一位够吗?
    • 如上面所说:元素从-1 dummynode开始,首先保存第2个元素(head.next.next)的值temp,而后dummynode(最开始为-1)指向第1个(head.next)元素,而第1个元素指向第0个(head)元素,最后第0个元素指向temp;而后pre与head各步进一位,即pre = head(此时pre为第1个元素),head = head.next(此时head为第2个元素),相当于pre,head从-1,0变成了1,2,这就相当于两节点平移了两位,刚好满足题目需要

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

题目链接

看到题目的第一想法:这题之前刷过,要删除倒数第n个元素(n从1开始,最后一个即为1),只需要找到前一个元素即可,pre其实位置为-1,移动len - n步之后刚好到待删除元素的前一位。

看完代码随想录之后的想法:卡哥的方法也很巧妙,双指针法,fast从-1开始,先移动n,而后两者同时移动,待fast移动至最后一个节点时,fast共移动len个,slow共移动len - n个(还剩n个未移动),此时为待删除节点的前一个节点。

代码实现:

  • 我的思路
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        int len = 0;
        ListNode dummy = new ListNode(-1);
        ListNode pre = dummy;
        dummy.next = head;
        while (pre.next != null) {
            len++;
            pre = pre.next;
        }
        pre = dummy;
        //pre移动len - n - 1 步之后刚好到待删除元素的前一位
        for (int i = 0; i < len - n; i++) {
            pre = pre.next;
        }
        ListNode temp = pre.next.next;
        pre.next = temp;
        return dummy.next;
}
  •   卡哥的解法

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        //卡哥的方法,双指针法,fast从-1开始,先移动n,而后两者同时移动,待fast移动至最后一个节点时
        //fast共移动len个,slow共移动len - n个,此时为待删除节点的前一个
        ListNode dummy = new ListNode(-1);
        ListNode pre = dummy;
        dummy.next = head;
        ListNode fast = dummy;
        ListNode slow = dummy;
        for (int i = 0; i < n; i++) {
            fast = fast.next;
        }
        //fast指向最后一个时,slow指向待删除节点前一个
        while (fast.next != null) {
            fast = fast.next;
            slow = slow.next;
        }
        slow.next = slow.next.next;
        return dummy.next;
    }
}

实现过程中遇到哪些困难:

  • 自己的思路与卡哥的解法中,需要移动多少个位置才能到待删除元素的前一个位置?
    • 都是移动了length - n个位置,前者从0开始,移动到了length - n - 1,后者slow也移动了length - n个位置,还有n个位置未移动,都能到待删除元素的前一个位置。

面试题 02.07  链表相交

题目链接

看到题目的第一想法:看到题目后没有思路,有无从下手的感觉

看完代码随想录之后的想法:卡哥的解法直接明确了若链表相交,从相交位置开始两链表完全是相等的,取较长的链表,而后将链表前部超出锻炼表的部分,相当于去掉(通过不断next的方式);两个链表一样长之后,比较是否相等,不相等则同时进行步进,相等则返回。

代码实现:

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        //自己想法比较乱,卡哥的解法看到后就感觉肯定可以解出题,很清晰
        int lenA = 0, lenB = 0;
        ListNode curA = headA;
        ListNode curB = headB;
        //要判断使用next的节点是否为null!!!!!!!!!!
        //别马虎大意了!
        while (curA != null) {
            lenA++;
            curA = curA.next;            
        }
        while (curB != null) {           
            lenB++;
            curB = curB.next;
        }
        curA = headA;
        curB = headB;
        //使A是较长的链表
        if(lenA < lenB) {
            ListNode temp = curA;
            curA = curB;
            curB = temp;

            int t = lenA;
            lenA = lenB;
            lenB = t;
        }
        
        int n = lenA - lenB;
        while (n-- > 0) {
            curA = curA.next;
        }
        //遍历新链表,相等则返回,不相等则向后移动
        while (curA != null) {
            if (curA == curB) {
                return curA;
            }
            curA = curA.next;
            curB = curB.next;
        }
        return null;
    }
}

实现过程中遇到哪些困难:

  • while循环的条件总是写错,经常未判断curA != null,而去直接判断curA.next != null,这是不可取的!!
    • 使用到next的时候要做非空判定~

142  环形链表 II

题目链接

看到题目的第一想法:看到题目之后没有思路,不知道如何模拟环形链表的情况。

看完代码随想录之后的想法:卡哥的方法通过模拟找出相遇的位置。卡哥是通过数学计算,来得到x = (n-1)(y+z) + z,若n = 1,即快指针在环里走了一圈多之后即遇到了满指针。所以有x = z,即从相遇位置每次步进一步,同时head每次步进一步,交点即为环的入口。

  • fast == slow时表示有环,fast从相遇的位置开始,每次前进一步;

    slow从head每次前进一步,相遇的位置即为环的入口

代码实现:

public class Solution {
    public ListNode detectCycle(ListNode head) {
        //无思路,卡哥的方法通过模拟找出相遇的位置每次步进一步,head每次步进一步,交点即为环的入口
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            //fast == slow时表示有环,fast从相遇的位置开始,每次前进一步;
            //slow从head每次前进一步,相遇的位置即为环的入口
            if (fast == slow) {
                ListNode index1 = fast;
                ListNode index2 = head;
                //此处即包含了快指针走>=1圈的情况 x = (n-1)(y+z) + z
                //n:快指针在环内走的圈数,n >= 1 
                //x:起始点到环入口的距离
                //y:入口至相遇点距离
                //z:相遇点至下一入口的距离
                while(index1 != index2) {
                    index1 = index1.next;
                    index2 = index2.next;
                }
                return index1;
            }
        }
        return null;
    }
}

实现过程中遇到哪些困难:

  • 如何表示快慢指针的相遇,fast == slow;
  • 如何表示fast在环中遇到slow指针,x = (n-1)(y+z) + z,n=1时,说明fast在链表中移动一圈多就和slow指针相遇了,n>=2时,下面代码也可以表示:
    •             if (fast == slow) {
                      ListNode index1 = fast;
                      ListNode index2 = head;
                      //此处即包含了快指针走>=1圈的情况 x = (n-1)(y+z) + z
                      //n:快指针在环内走的圈数,n >= 1 
                      //x:起始点到环入口的距离
                      //y:入口至相遇点距离
                      //z:相遇点至下一入口的距离
                      while(index1 != index2) {
                          index1 = index1.next;
                          index2 = index2.next;
                      }
                      return index1;
                  }
  • 为什么第一次在环中相遇,slow的 步数 是 x+y 而不是 x + 若干环的长度 + y 呢?
    • 见链接
    • 首先slow进环的时候,fast一定是先进环来了。

      如果slow进环入口,fast也在环入口;可以看出如果slow 和 fast同时在环入口开始走,一定会在环入口3相遇,slow走了一圈,fast走了两圈。重点来了,slow进环的时候,fast一定是在环的任意一个位置,如图

今日收获,记录一下自己的学习时长

  • 算法处理约3h,博客编写约2h
  • 熟悉了链表的交换,删除,相交与环~
  • 贵在坚持,加油!

 链表总结:

  • 虚拟头节点,链表基本操作,链表移除,反转,相交,环形都很重要~
  • 链表相对于数组来说不太直观,需要投入更多精力,要多复习~
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值