代码随想录算法训练营第四天| 链表part02,24.两两交换链表中的节点 ,19.删除链表的倒数第N个节点,02.07.链表相交,142.环形链表II

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

思路:在看了讲解文章后,大概有了解题的思路,虽然和卡尔的代码有些出入,但大体上是相同的,在更新current和pre指针的时候踩了一个小坑,在完成两个节点的交换更新current和pre指针时,注意要先更新pre,再更新current!!代码如下:

class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dummyHead = new ListNode(-1, head);
        ListNode current = head;
        ListNode pre = dummyHead;
        while(current != null && current.next != null){
            ListNode temp = current.next; 
            pre.next = temp;
            current.next = temp.next;
            temp.next = current;
            pre = current;
            current = current.next;
        }
        return dummyHead.next;
    }
}

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

原始思路:先用一个循环遍历链表,记录链表总长度,再用一个for循环从头遍历链表,找到第N个节点的前一个节点,再删除保存,但不知道为啥代码会报空指针,也不知道咋改,只好去看讲解的文章。

看了文章后醍醐灌顶,只用一次循环就能解决该问题,真是妙不可言呀!

思路:双指针解法,先让fast指针先走n+1步,然后slow指针和fast指针同时更新遍历,直到fast等于null,此时的slow指向倒数第N个节点的前一个节点,便于进行删除操作。上代码:

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummyHead = new ListNode(-1, head);
        ListNode fast = dummyHead;
        ListNode slow = dummyHead;
        int nums = n+1;
        while(fast != null){
            if(nums == 0){
                fast = fast.next;
                slow = slow.next;
            }else{
                fast = fast.next;
                nums--;
            }
        }
        if(slow.next != null){
            slow.next = slow.next.next;
        }
        return dummyHead.next;
    }
}

也许是之前一直都是用双指针解决数组相关问题,在处理链表问题时即使提示用双指针,还是没有思路,看来还是要总结一下,什么时候可以用双指针解法,或者说使用双指针法需要满足哪些条件?

面试题02.07链表相交

原始想法:刚看到本题,想到的解法是类似于数组的尾部对齐,需要先遍历两个数组得到数组长度才能对齐,也是实在想不出用双指针该怎么解,就去看了讲解文章(我一般是先看思路,自己写题,然后在看文章中的代码)。

思路:看了文章之后,发现也是对其然后找起点,对齐过程的处理有点像上题中快慢指针找倒数第N个节点的解决相似。

按照这个思路写题,虽然通过了,但代码十分冗余,于是便优化了一下:假设长度大的链表为maxList,长度小的链表为minList,再按照思路解题,代码就没有那么冗余啦,代码如下:

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode maxList = headA;
        ListNode minList = headB;
        int countA = 0;
        int countB = 0;
        int steps = 0;
        while(maxList != null){
            countA++;
            maxList = maxList.next;
        }
        while(minList != null){
            countB++;
            minList = minList.next;
        }
        if(countA >=countB){
            steps = countA - countB;
            maxList = headA;
            minList = headB;
        }else{
            steps = countB - countA;
            maxList = headB;
            minList = headA;
        }
        while(maxList != null){
                if(steps == 0){
                    if(maxList == minList){
                        return maxList;
                    }
                    minList = minList.next;
                }else{
                    steps--;
                }
                maxList = maxList.next;
            }
        return null;
    }
}

LeetCode 142.环形列表II

看了题但是没啥思路就直接看了讲解的文章,看明白了解题的思路,自己写了一遍,但是循环的遍历条件没写对,我写的是fast != slow && fast != null,由于定义的时候都是head,所以在进循环之前就对fast和slow先进行了一轮赋值,然后报空指针,哈哈哈哈哈,小菜鸡果然是小菜鸡,最终看了答案,发现我循环条件写错了,仔细想想这样写确实最好,我那样写只考虑了有环的情况但是忽略了正常的链表遍历的边界条件。

思路:分两步走:1.是否有环;2.环的入口在哪里?本题可以使用快慢指针来判断是否有环,快指针即每次走两步,慢指针即每次走一步,在遍历过程中若它们相等则说明有环,在有环的前提下,重新同时从起点和相遇点开始每次走一步,则再次相等的节点就是环的入点。代码如下:

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        while(fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow){
                ListNode start = slow;
                fast = head;
                while(fast != start){
                    fast = fast.next;
                    start = start.next;
                }
                return start;
            }
        }
        return null;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值