Day4:Leetcode24两两交换链表中的结点,Leetcode19删除链表倒数第n个结点,Leetcode142环形链表

今日鸡汤:“遗憾谁没有呢?人往往都是快死的时候,才发现人生最大的遗憾就是一直在遗憾过去的遗憾。”

1. 两两交换链表中的结点LeetCode24

题目:
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
示例:
输入:head = [1,2,3,4]
输出:[2,1,4,3]

思路:
1.一开始有想到用虚拟结点dummy以及cur去遍历,但是发现是死循环…可恶,然后发现自己想得很复杂,用了pre,cur,next三个指针,导致自己又被绕进去了…
(不过鼓励鼓励自己就是,今天还有一点进步就是已经想到了Dummy结点这个东西!每天进步一点点nice!)
2.本题需要注意事项:
操作链表结点时一定要注意,你需要找的是需要操作结点的前一个结点,才能操作结点。
while循环中的判断顺序不能改变,不然可能会出现操作空指针的报错。

 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode swapPairs(ListNode head) {
       ListNode dummy=new ListNode(-1,head);
       ListNode cur=dummy;
       //注意操作指针要指向反转结点的前一个结点。
       while(cur.next!=null && cur.next.next!=null){
           //注意两个判断顺序不能出错,不然当cur.next为空时,会出现操作空指针的现象
           ListNode temp=cur.next;
           ListNode temp1=cur.next.next.next;

           cur.next=cur.next.next;
           cur.next.next=temp;
           temp.next=temp1;
           //cur.next.next.next=temp1;
           cur=cur.next.next;
           //temp.next=temp1;
           //cur=temp1;操作结点时需要指向结点前面一个结点的元素才可以
       }
       return dummy.next;
}
}

2.删除链表倒数第n个结点Leetcode19

题目:
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
示例:
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]

思路:
1.对于自己而言,一开始思考还是只会用暴力思维(或者更像数组的思维方式)就是希望先找到最后一个元素,再往回走,但是这里需要注意的是,这样做时,我自己也不知道该怎么弄指针
2.正确思路:快慢指针法
首先,如果先让快指针走n步,之后快慢指针同时前进的话,其实最后当快指针到尾结点的时候,慢指针走到的是第n个结点。但是操作某结点时,需要的是找到它的前一个结点,通过前一个结点的指针进行操作,因此快指针需要提前走n+1步。

(发现理解原理之后,写代码快多了)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy=new ListNode(-1,head);
        ListNode fast=dummy;
        ListNode slow=dummy;

            for(int i=1;i<=n+1;i++){
                fast=fast.next;
            }//快指针需要先走n+1步,从而让慢指针停在倒数第n个元素的前一个元素

            while(fast!=null){
                slow=slow.next;
                fast=fast.next;
            }
            slow.next=slow.next.next;
        return dummy.next;

    }
}

3.链表相交面试题02.07

题目:
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
示例:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at ‘8’
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。思路:
可以利用快慢指针的思路解决。(假设长链的为A,短链为B)
其实从上面的图就可以看到,如何两条链相交的话,长链指针一定要比短链先移动lenA-lenB,这样再去比较之后的元素指针是否相同即可。

这里需要注意的是,为了方便起见,可以认为将长短链进行调整。
调整两者的长度以及头结点的指针即可。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        int lenA=0;
        int lenB=0;
        ListNode curA=headA;
        ListNode curB=headB;
    
        while(curA!=null){
            lenA+=1;
            curA=curA.next;
        }
        while(curB!=null){
            lenB+=1;
            curB=curB.next;
        }

        curA = headA;
        curB = headB;
        // 让curA为最长链表的头,lenA为其长度
        if (lenB > lenA) {
            //1. swap (lenA, lenB);
            int tmpLen = lenA;
            lenA = lenB;
            lenB = tmpLen;
            //2. swap (curA, curB);
            ListNode tmpNode = curA;
            curA = curB;
            curB = tmpNode;
        }

        int gap=lenA-lenB;

        for(int i=gap;i>0;i--){
            curA=curA.next;
        }
        while(curA!=null){
            if(curA==curB){
                return curB;
            }
            curA=curA.next;
            curB=curB.next;
        }
        return null;
        
    }
}

环形链表Leetcode142

题目:
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

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

不允许修改 链表。

示例:
在这里插入图片描述

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。

思路:
该题思路建议参考卡哥的讲解,真的很妙!!(菜鸡能做的只有理解然后复现代码罢了)环形链表

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
        public ListNode detectCycle(ListNode head) {
        ListNode slow = head;
        ListNode fast = head;
        while (fast != null && fast.next != null) {
            //快指针的步长是2,慢指针的步长是1,所以如果有环,那么在环中,快指针一定会追上慢指针。
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {// 有环
                ListNode index1 = fast;
                ListNode index2 = head;
                // 两个指针,从头结点和相遇结点,各走一步,直到相遇,相遇点即为环入口
                while (index1 != index2) {
                    index1 = index1.next;
                    index2 = index2.next;
                }
                return index1;
            }
        }
        return null;
    }
        
}

PS:
怎么说呢,感觉最近充实了很多,毕竟写代码真的挺耗时间的哈哈哈,算是消磨时间的好去处了,尤其是当你遇到一个非常非常非常无语的bug的时候hhh。
希望自己能够坚持下去!!!加油!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值