随想录训练营4/60 | LC 24 两两交换链表中的节点;LC 19 删除链表的倒数第N个节点;LC 面试题 02.07. 链表相交;LC 142 环形链表II

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

题目链接LC 24 两两交换链表中的节点
思路:为了代码更优雅,加上虚拟头节点,但是返回的时候要返回真实的头节点。两个节点之间交换容易,但是要注意交换后两节点与前后节点之间的联系,这也是引入虚拟头节点的原因之一。
具体按随想录中设两个temp,按结果的顺序来传递。这样容易缕清思路。
例如,交换0->1->2->3->4中的2与3:先1->3,再3->2,最后2->4,这样需要temp1保存2的地址(1->3之后就找不到2了),temp2保存4的地址(3->2之后就找不到4了)
也可以只设一个temp,按下面例子的思路。
例如,交换0->1->2->3->4中的2与3:先1->3,再2->4,最后3->2,这样只需要temp1保存2的地址即可。把交换2,3位置改为了两步,第一步删除2,第二步把2放到3后面
代码

/**
 * 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) {}
 * };
 */
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummy = new ListNode(0);
        dummy->next = head;
        ListNode* cur = dummy;
        while(cur->next!=nullptr && cur->next->next!=nullptr){//第一种情况是偶数个,第二种情况是奇数个(不包括虚拟头节点)
            ListNode* temp = cur->next;
            cur->next = temp->next;
            temp->next = cur->next->next;
            cur->next->next = temp;
            cur = temp;
        }
        return dummy->next;
    }
};

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

题目链接LC 19 删除链表的倒数第N个节点
思路:这个题目解决办法看一遍就忘不了了。一个指针r先走k+1步,另一个指针l重头开始,两个指针一起走,直到r到了链表尾,l指向的是倒数第k+1个节点。然后再删除倒数第k个节点。也要设置虚拟头节点,不然不好删除头节点。
两指针走的时候要注意细节
代码

/**
 * 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) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummy = new ListNode(0);
        dummy->next = head;
        ListNode* r = dummy;
        ListNode* l = dummy;
        for(int i=0; i<n; ++i){//让r先走n步
            r = r->next;
        }
        while(r->next!=nullptr){//r,l一起走
            r = r->next;
            l = l->next;
        }
        ListNode* temp = l->next;
        l->next = temp->next;
        delete temp;
        return dummy->next;//不能是head,因为删除的节点可能是head
    }
};

LC 面试题 02.07. 链表相交

题目链接 LC 面试题 02.07. 链表相交
思路:相交的情况一定是从某个节点开始两个链表的节点地址就一样了,直至链表末尾(因为相交的节点地址相同,所以next也一定都相同)。解题思路就是,将两链表的末尾对齐后遍历。先遍历两个链表,得到它们的长度,然后做差,长的先遍历,然后同时遍历直到节点的地址相同。
代码

/**
 * 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 lenA = 0;
        int lenB = 0;
        ListNode* curA = headA;
        ListNode* curB = headB;
        while(curA!=nullptr){//有可能是空链表,所以即使是长度做差也要遍历到底,不然空链表curA->next超出范围
            ++lenA;
            curA = curA->next;
        }
        while(curB!=nullptr){
            ++lenB;
            curB = curB->next;
        }
        int x = lenA-lenB;
        curA = headA;
        curB = headB;
        if(x>=0){
            while(x){
                curA = curA->next;
                --x;
            }
            while(curA!=nullptr){
                if(curA==curB)return curA;
                curA = curA->next;
                curB = curB->next;
            }
        }
        else{
            x = -x;
            while(x){
                curB = curB->next;
                x--;
            }
            while(curA!=nullptr){
                if(curB==curA)return curA;
                curA = curA->next;
                curB = curB->next;
            }
        }
        return nullptr;
    }
};

LC 142 环形链表II

题目链接LC 142 环形链表II
思路:有两个基本问题。1.链表是否有环? 2.环的入口在哪里?
解决第一个问题:快慢指针法,快指针每步走两个节点,慢指针每步走一个节点,若慢指针到链表尾,两指针仍未相遇,则没有环。分析:当没有环的时候,两个指针不会相遇。当有环的时候,在慢指针到环的入口的时候,快指针已经进入环,假设快指针在环的任意位置,相当于快指针开始追慢指针,之后两指针的距离每步减一,因此两指针定会相遇。
解决第二个问题:假设两个指针已相遇,令两个指针分别从相遇点和起点开始每步走一个节点,相遇点则为入口。推导思路如下,建议自己推一下,不难。
环形链表推导

代码

/**
 * 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* f = head;//fast
    //     ListNode* s = head;//slow
    //     int flag = 0;//防止只有一个节点且节点没有环的情况
    //     while(f!=nullptr&&f->next!=nullptr){
    //         flag = 1;
    //         s = s->next;
    //         f = f->next->next;
    //         if(s==f)break;
    //     }
    //     if(flag==0 || s!=f)return nullptr;
    //     //s为相遇点
    //     ListNode* h = head;
    //     while(h!=s){
    //         h = h->next;
    //         s = s->next;
    //     }
    //     return s;
    // }
    ListNode *detectCycle(ListNode *head) {
        ListNode* f = head;//fast
        ListNode* s = head;//slow
        while(f!=nullptr&&f->next!=nullptr){
            s = s->next;
            f = f->next->next;
            if(s==f){
                f = head;
                while(f!=s){
                    f = f->next;
                    s = s->next;
                }
                return s;
            }
        }
        return nullptr;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值