代码随想录训练营day04: 链表pairs交换, 删除倒数第k个节点, 链表相交, 环形链表

训练营第四天了, 也进入周末了, 还是得趁周日把之前的重新写几遍,不然就忘了; 关于链表的话话题更可以帮助理解, 重点无非就是理解指针谁指向谁, cur放在哪里,加油吧南部武士

 

两两交换链表中的节点

思路, 和之前的大同小异,只不过要考虑指针的方向,和建立多个临时节点, 首先还是要虚拟头节点, 然后cur节点指向它, 进入while循环, 这里使用短路和&&要重视, 首先用temp保存节点一和节点三, 然后cur指向第二个节点, 第二个指向第一个, 第一个指向第三个, 执行完将cur指针后移两位就行了 

(细节: 记得把dummy.next = head, 不然就啥都没执行了)

class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dummy = new ListNode(0);
        ListNode cur = dummy;
        dummy.next = head;
        while(cur.next != null && cur.next.next != null){
            ListNode temp = cur.next;
            ListNode temp1 = cur.next.next.next;
            cur.next = cur.next.next;  //让头节点指向节点二
            cur.next.next = temp;   //让节点二指向节点一
            temp.next = temp1;      //让节点一指向节点三
            cur = cur.next.next;   //向前移动两个
        }
        return dummy.next;
    }
}

补充:

区别&&只要第一个条件不满足,后面条件就不再判断。

&要对所有的条件都进行判断。

区别是||只要满足第一个条件,后面的条件就不再判断。

|要对所有的条件进行判断

==================================================================================================================================================================================

删除链表倒数第n个节点

思路: 这里有多种思路, 包括韩顺平讲的先获取长度, 再length - index + 1; 也可以用栈; 也可以用双指针, 这里用双指针分析一下: 一个快指针,一个慢指针, 快指针去前面先走n+1步,然后慢指针开始走,直到快指到null, 这样可以保证slow停在待删除节点的前面

细节:
1. 有两个循环, 第一个循环条件是 n-- > 0, 也就是走n步,循环结束后再写一遍fast = fast.next; (也可以直接写n-- >= 0)

2. 第二个循环就简单判断 (fast != null), 之后return dummy.next;

(记得是dummy.next = head,然后指针是直接到dummy的)

(移动n步, 就n-- > 0, 移动n+1步, 就n-- >= 0)

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode fast = dummy;
        ListNode slow = dummy;
        while(n-- >= 0){
            fast = fast.next;
        }
        //fast = fast.next; //再多走一步, 让slow停在待删除节点前面一个
        while(fast != null){
            fast = fast.next;
            slow = slow.next;
        }
        slow.next = slow.next.next;
        return dummy.next;
    }
}

==============================================================================================================================================================================

链表相交

这题有两个解法

先遍历长度再, 让他们到同一个节点, 之后遍历判断是否相同

思路:

  1. 定义int lenA, lenB, 和节点curA, curB
  2. 利用求出A链表长度, B链表长度
  3. 让curA始终是长的那一个, 所以判断lenA < lenB, 否则调换len和cur(要temp)
  4. 求出AB长度差, 然后让A先走gap, 到达同一起点
  5. 开始遍历判断if curA == curB, return curA, 否则AB后移, 如果遍历完了还没return curA说明AB不相等, 直接return null.

注意细节: 遍历完AB求完长度之后, 需要重新定义到头节点初始化, 否则会空指针异常

记得gap-- > 0 就是移动gap步; 记得加ListNode

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode curA = headA;
        ListNode curB = headB;
        int lenA = 0, lenB = 0;
        while(curA != null){
            lenA++;
            curA = curA.next;
        }
        while(curB != null){
            lenB++;
            curB = curB.next;
        }
        //求完长度之后,要重新定义cur,让他们回到开头
        curA = headA;
        curB = headB;
        if(lenA < lenB){
            //调转长度
            int tempL = lenA;
            lenA = lenB;
            lenB = tempL;
            //调转节点
            ListNode tempN = curA;
            curA = curB;
            curB = tempN;
        }
        //计算gap,并让curA和curB在同一起点
        int gap = lenA - lenB;
        while(gap-- > 0){
            curA = curA.next;
        }
        while(curA != null){
            if(curA == curB){
                return curA;
            }
            curA = curA.next;
            curB = curB.next;
        }
        return null;
    }
}

双指针解法

如果他们相交, 可以发现, 他们走完之后互换位置到c的距离是相等的

1.先判断这两个head是否为null

2.定义两个指针, 如果其中一个为null了(指到最后一个了), 就切换到另一个节点, 如果不是就继续往后走

3.当他们两个相等时, 就直接return, 就算不相交, 也是相等的,会return null

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

================================================================================================================================================================================

接下来是链表的最后一题

环形链表II

判断链表是否有环: 利用双指针判断, 如果快慢指针相遇了, 说明有个环

快指针一次移动两个节点

慢指针一次移动一个节点

找到环的入口:

slow = x + y

fast = x +y + n(y+z)

得出x = z, 也就是说他们总会在入口处相遇,所以可以定义index1=fast, index2=head;

细节注意:

while循环是包括了中间的大块代码的, 如果while遍历完没有执行中间的, 说明没有环

1.建立快慢指针

2.利用while循环, 来让他们以不同速度移动, 直到fast 和 fast.next为null

3. 判断是否slow = fast, 如果是, 就继续执行index的循环, 当index相遇, 那个点就是环入口

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        //快指针走在前面, 所以判断不为空, next也要因为他是两步一跳
        while(fast != null && fast.next != head){
            fast = fast.next.next;
            slow = slow.next;
            //如果两个相遇了, 说明有个环
            if(slow == fast){
                //继续定义index, 来找到入口
                ListNode index1 = fast;
                ListNode index2 = head;
                //因为肯定会相交, 所以循环结束直接return
                while(index2 != index1){
                    index1 = index1.next;
                    index2 = index2.next;
                }
                return index1;
            }
        }
        //如果这个大的循环没有相遇, 说明没有环
        return null;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值