【链表2】24. 两两交换链表中的节点 19.删除链表的倒数第N个节点 面试题 02.07. 链表相交 142.环形链表II

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

题目链接

(1)文字讲解:https://programmercarl.com/0024.两两交换链表中的节点.html#思路
(2)视频讲解:
(3)题目链接:https://leetcode.cn/problems/swap-nodes-in-pairs/

看到题解之前的想法

一开始理解错题目的意思了,以为需要先转12,再转23,再34,但是本题只要求转12后转34,再56,就可以了。

看到题解之后的想法

1.做链表的题目一定要清楚每个步骤的先后顺序,先后修改哪个节点的next;然后如果中途你有因为改变next而失去联系的某些节点,用tmp去记录就好。
2.这一题其实没有定死改变的先后顺序,我自己写的虽然和题解有出入但是也是对的。
(1)我写的:
在这里插入图片描述
(2)题解写的:
在这里插入图片描述

本题难点

1.理清楚改变next的前后关系
2.确定用tmp临时保存哪个节点

代码

我写的:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
// struct ListNode{
//     int val;
//     ListNode *next;
//     ListNode(): val(0), next(nullptr){}
//     ListNode(int val): val(0), next(nullptr){}
//     ListNode(int val, ListNode* next): val(val), next(next){}
// };

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode *dummyhead = new ListNode(0, head);
        ListNode *cur = dummyhead;
        ListNode *tmp = NULL;
        while(cur->next && cur->next->next){
            tmp = cur->next;
            cur->next = cur->next->next;
            tmp->next = tmp->next->next;
            cur->next->next = tmp;
            cur = tmp;
        }
        return dummyhead->next;
    }
};

题解写的:

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummyHead = new ListNode(0); // 设置一个虚拟头结点
        dummyHead->next = head; // 将虚拟头结点指向head,这样方便后面做删除操作
        ListNode* cur = dummyHead;
        while(cur->next != nullptr && cur->next->next != nullptr) {
            ListNode* tmp = cur->next; // 记录临时节点
            ListNode* tmp1 = cur->next->next->next; // 记录临时节点

            cur->next = cur->next->next;    // 步骤一
            cur->next->next = tmp;          // 步骤二
            cur->next->next->next = tmp1;   // 步骤三

            cur = cur->next->next; // cur移动两位,准备下一轮交换
        }
        return dummyHead->next;
    }
};

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

题目链接

(1)文字讲解:https://programmercarl.com/0019.删除链表的倒数第N个节点.html#思路
(2)视频讲解:
(3)题目链接:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/description/

看到题解之前的想法

不知道怎么做,因为他是要删除倒数的第n个节点,而链表的长度是不知道的,如果正常来说,先要遍历一遍链表得到长度,然后返回去n个。但是这个题目要求一趟扫描实现。

看到题解之后的想法

1.双指针,fast指针先走n步,然后slow和fast一起动,直到fast指向最后一个节点,这时候fast已经走了链表长度l的步数,slow走了l-n步,也就是说现在slow就指向了倒数第n个节点。
2.但是为了方便删除操作,fast需要走n+1步,因为这样slow就会走到被删除的节点的前一个节点。
3.加一个虚拟头节点后,相当于链表长度变长了,fast和slow相对关系不变,只是判断条件从fast到最后一个节点变成fast指向空(相当于l+1)。
4.如果你的判断条件是while(fast->next),那么相当于你缩短了fast走的长度,那么n不应该加一,就可以让slow指向被删除节点的前一个节点。

本题难点

1.双指针
2.想明白while判断条件和n是否++。

代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
//  struct ListNode{
//      int val;
//      ListNode *next;
//      ListNode(): val(0), next(nullptr){}
//      ListNode(int val): val(val), next(nullptr){}
//      ListNode(int val, ListNode* next): val(val), next(next){}
//  }
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode *dummyhead = new ListNode(0, head);
        ListNode *slow = dummyhead;
        ListNode *fast = dummyhead;
        n++;
        while(n--){
            fast = fast->next;
        }
        // while(fast->next)
        while(fast){
            slow = slow->next;
            fast = fast->next;
        }
        ListNode *tmp = slow->next;
        slow->next = slow->next->next;
        delete tmp;
        return dummyhead->next;
    }
};

面试题 02.07. 链表相交

题目链接

(1)文字讲解:https://programmercarl.com/面试题02.07.链表相交.html
(2)视频讲解:
(3)题目链接:https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/description/

看到题解之前的想法

不知道怎么做,因为直观的办法就是暴力,对于每一个A链表中的节点,都遍历B链表中的节点看一下是否有相等的。

看到题解之后的想法

1.首先求出A,B两个链表的长度
2.然后让A,B两个链表在尾部对齐。如果A和B有相交的地方,说明A和B的尾部一定是对齐的。从短的链表的开头,以及长的链表的和短链表的对齐处开始比较,一旦相等,就是答案了。
在这里插入图片描述

本题难点

1.正着找相交点因为长度不同所以不好找,因此反着找。
2.节点相等是地址一致,不是val相等。

代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        int sizeA = 0, sizeB = 0, offset = 0, result = 0;
        ListNode *curA = headA;
        ListNode *curB = headB;
        while(curA){
            curA = curA->next;
            sizeA++;
        }
        while(curB){
            curB = curB->next;
            sizeB++;
        }
        curA = headA;
        curB = headB;
        if(sizeA > sizeB){
            offset = sizeA - sizeB;
            while(offset--){
                curA = curA->next;
            }
        }else{
            offset = sizeB - sizeA;
            while(offset--){
                curB = curB->next;
            }
        }
        // result = offset;
        bool flag = 0;
        while(curA && curB){
            if (curA == curB){
                flag = 1;
                break;
            }
            curA = curA->next;
            curB = curB->next;
        }
        if(flag){
            return curA;
        }else{
            return NULL;
        }
    }
};

142.环形链表II

题目链接

(1)文字讲解:https://programmercarl.com/0142.环形链表II.html#思路
(2)视频讲解:
(3)题目链接:https://leetcode.cn/problems/linked-list-cycle-ii/description/

看到题解之前的想法

只知道用快慢指针判断链表是否有环,但是不知道怎么给出环开始的节点。

看到题解之后的想法

1.双指针,fast指针每次走两步,slow指针每次走一步,如果slow和fast能够相遇,说明有环。
2.如果把slow和fast指针的相遇轨迹画一个图,那就如下:
在这里插入图片描述
slow指针的步数:x+y
fast指针的步数:x+y+n*(z+y)

为什么不可能是slow也转了m圈之后才遇到fast呢?因为假设slow进入环的时候,fast刚刚从入口走过一步(这是两个指针在环中相差最大的时候了),那么fast每次走两步,slow每次走一步,fast走完两个环,slow刚好走完一个环,他们在入口相遇,这是相差最大的情况,如果是其他的情况,他们会更早相遇,也就是slow不会走超过一圈

fast的步数是slow的两倍,也就是2*(x+y) = x+y+n*(z+y)
整理可得:x = (n - 1) (y + z) + z
如果n=1,那么x=z,也就是让一个节点从head开始走,一个节点从相遇点开始走,他们两个节点相遇的时候就是环的入口
如果n>1,那也没事,反正他俩相遇的时候就是环的入口。
3.我写的时候,思路是先判断是否有环,所以先写了一个while循环,如果相遇,break,然后从fast是否为空判断是否相遇了。

        while(fast){
            fast = fast->next->next;
            slow = slow->next;
            if(fast == slow){
                break;
            }
        }
        if(fast == NULL){
            return NULL;
        }

但是这样写是有问题的,因为当链表为奇数个的时候,fast每次走两步,到末尾的一步的时候,fast = fast->next->next;会报错。所以在while里面要加一个fast->next!=NULL。加了这个之后,下面的if也要加,因为这两种null都说明这个链表是有尽头的,不是环。

        while(fast && fast->next){
            fast = fast->next->next;
            slow = slow->next;
            if(fast == slow){
                break;
            }
        }
        if(fast == NULL or fast->next == NULL){
            return NULL;
        }

本题难点

1.双指针判断时候有环
2.根据图和fast与slow的关系,列出公式得出x和z的关系,从而算出环的进入点

代码

我写的:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if (head == NULL) return NULL;
        if (head->next == NULL) return NULL;
        ListNode *slow = head;
        ListNode *fast = head;
        while(fast && fast->next){
            fast = fast->next->next;
            slow = slow->next;
            if(fast == slow){
                break;
            }
        }
        if(fast == NULL or fast->next == NULL){
            return NULL;
        }
        ListNode *cur = head;
        while(cur){
            if(slow == cur){
                break;
            }
            cur = cur->next;
            slow = slow->next;
        }
        return cur;
    }
};

题解写的:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *slow = head;
        ListNode *fast = head;
        while(fast && fast->next){
            fast = fast->next->next;
            slow = slow->next;
            if(fast == slow){
                ListNode *node1 = head;
                ListNode *node2 = fast;
                while(node1 != node2){
                    node1 = node1->next;
                    node2 = node2->next;
                }
                return node1;
            }
        }
        return NULL;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值