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

文档讲解:

24:https://programmercarl.com/0024.%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B9.html19:https://programmercarl.com/0019.%E5%88%A0%E9%99%A4%E9%93%BE%E8%A1%A8%E7%9A%84%E5%80%92%E6%95%B0%E7%AC%ACN%E4%B8%AA%E8%8A%82%E7%82%B9.html160:https://programmercarl.com/%E9%9D%A2%E8%AF%95%E9%A2%9802.07.%E9%93%BE%E8%A1%A8%E7%9B%B8%E4%BA%A4.html142:https://programmercarl.com/0142.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8II.html

解题思路:

24:这题的核心精髓是定义了两个temp指针,分别是temp1和temp2,前者指向要交换位置的一组结点的第一个元素,后者指向后一组要交换位置的一组结点的第一个元素,因为我们在交换一组元素时会不可避免地覆盖或者丢失一些元素的地址。还有一点要强调一下,那就是注意while循环里面要先写一个next以防写先写两个next会发生编译错误(因为有可能压根儿就没有两个next了)。

19:这题的方法我们必需要掌握,那就是利用双指针解题。具体方法为要想着怎么找到倒数的某一个结点,这里我们设置了前后两个指针,分别是pre和cur,先让cur往链表前面走,比如找倒数第N个,那就让cur往前面走N步,这样等到循环结束条件完成时即cur到NULL时,pre正好到了要删结点的前一个,这样就能很方便地删除该结点了,比较巧妙。

160:这一题刚开始我使用暴力解法,时间复杂度非常高,因为我设置了两个循环,强行地去找两个链表有没有相交的结点,但是我通过学习代码随想录,了解到了一种极为精巧的解法。我们首先需要测量两个链表的长度,然后规定长的是A(这可以通过交互两个头结点指针实现),固定了长的链表后就测量出两个链表的长度差gap,紧接着关键的部分来了,我们将较长的A链表的头结点赋给指针curA(B也是一样),再讲curA往前移动gap位,此时我们会发现两个链表的头指针已经对齐了,接着就好办了,直接同时遍历两个链表的指针观察有没有相同的指针出现,有就循环终止返回该指针,循环遍历完没有就直接返回NULL了。

142:该题需较为仔细地去分析得出一些数学关系,比如我们知道了快慢指针(fast and slow)必然再slow指针第一次进入环的时候相遇,并且后面在开头设置index2指针和在相遇点设置index1指针,它们两个必然在我们要找的那个环入口结点相遇等。具体而言,首先fast每次前进两个单位而slow仅一个单位,并且循环条件是判断是否有环的关键,进入循环并且进入循环内的if语句就说明了有环并且相遇的,然后记录位置为index1再求跟index2相遇的结点返回就可以了,如果循环都进入不了则说明根本就构不成环!

详细代码如下:

//24
/**
 * 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* dummyhead=new ListNode();
        dummyhead->next=head;
        ListNode* cur=dummyhead;
        while((cur->next!=nullptr)&&(cur->next->next!=nullptr)){
            ListNode* temp1=cur->next;
            ListNode* temp2=cur->next->next->next;
            cur->next=cur->next->next;
            cur->next->next=temp1;
            temp1->next=temp2;
            cur=cur->next->next;
        }
        return dummyhead->next;    
    }
};
//19
/**
 * 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* dummyhead=new ListNode();
        dummyhead->next=head;
        ListNode* cur=dummyhead;
        ListNode* pre=dummyhead;
        pre=dummyhead;
        cur=dummyhead;
        while(n){
            cur=cur->next;
            n--;
        }
        while(cur->next!=nullptr){
            pre=pre->next;
            cur=cur->next;
        }
        pre->next=pre->next->next;
        return dummyhead->next;
        delete dummyhead;    
    }
};
//160
/**
 * 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;
        int gap=0;
        while(curA!=NULL){
            lenA++;
            curA=curA->next;
        }
        while(curB!=NULL){
            lenB++;
            curB=curB->next;
        }
        curA=headA;
        curB=headB;
        if(lenA<lenB){
            ListNode* temp;
            temp=curA;
            curA=curB;
            curB=temp;
            gap=lenB-lenA;
        }
        else{
            gap=lenA-lenB;
        }
        while(gap){
            gap--;
            curA=curA->next;
        }
        while(curA!=curB){
            curA=curA->next;
            curB=curB->next;
        }
        if(curA==curB){
            return curA;
        }
        else return NULL;
        
    }
};
//142
/**
 * 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* fast=head;
        ListNode* slow=head;
        while(fast!=NULL&&fast->next!=NULL){
            fast=fast->next->next;
            slow=slow->next;
            if(fast==slow){
                ListNode* index1=fast;
                ListNode* index2=head;
                while(index1!=index2){
                    index1=index1->next;
                    index2=index2->next;
                }
                return index1;
            }
        }
        return NULL;
        
    }
};

解题总结:今日题目教会了我们一些经典题目的解法,如找倒数就用双指针;找两个列表的交点结点就平移两个链表头结点指针一致然后分别遍历,然后交换或者对链表进行一些改变是就要主意利用temp指针临时保存需要操作的变量结点的地址,以备后用。最后就是环有关的题目就用快慢指针,能相遇就有环等。总之需不断练习某一数据结构或者某算法的题目并且及时总结才能使我们的算法水平不断提高与巩固。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值