代码随想录第四天 leetcode 24、19、206

这篇博客详细讲解了四个关于链表的经典算法问题:LeetCode24题的两两交换链表节点,LeetCode19题的删除链表倒数第N个节点,链表相交的节点查找,以及环形链表的检测与入口查找。每个问题都提供了详细的解题思路和关键代码片段,涉及双指针法、虚拟头节点等技巧。通过这些例子,深入理解链表操作和算法设计。
摘要由CSDN通过智能技术生成

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

首先本题需要使用虚拟头节点,因为交换两个节点的操作时,cur指针一定要指向这两个节点的前一个节点,所以在完成一次交换之后,cur指针应该指向当前交换完成的两个节点中的后一个节点。其次因为需要断开两个节点,所以需要用两个temp指针来保存,具体需要保存的节点经过模拟发现一个时交换的前一个结点和后一个结点的next结点。
下面给出代码:

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummyhead = new ListNode(0);
        dummyhead->next = head;
        ListNode* cur = dummyhead;
        while(cur->next != NULL && cur->next->next != NULL){
            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;
    }
};

需要注意的是:while条件中注意判断顺序会导致空指针异常,需要先判断next再判断next的next。

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

  1. 最暴力的方法就是,先反转,然后删除第n个结点,再反转即可。
  2. 第二种方法就是首先找到链表的长度len,然后删除第len - n个结点即可
  3. 第三种方法是卡哥的方法,使用双指针法,首先让fast先走n个结点,然后让快慢指针同时移动,当fast指向NULL时,就可以找到需要删除的结点。下面给出代码:
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyhead = new ListNode(0);
        dummyhead->next = head;
        ListNode* fast = dummyhead;
        ListNode* slow = dummyhead;
        n = n + 1;
        while(n--){
            fast = fast->next;
        }
        while(fast != NULL){
            fast = fast->next;
            slow = slow->next;
        }
        ListNode* temp = slow->next;
        slow->next = slow->next->next;
        delete temp;
        return dummyhead->next;

    }
};

代码在处理细节的时候会有不同,不过只要是删除结点,使用虚拟头节点即可,最后让slow指针指向需要删除的结点的前一个结点。

面试题 02.07. 链表相交

本题还是使用双指针法,首先算出两个链表的长度,然后再进行指针移动。需要注意的是:

  • 只要两个指针指向的结点cura == curb就代表后续所有的结点都相同
  • 需要找到较长的那个链表,并让其先移动两个链表长度差值的长度

下面给出代码:

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        int sizea = 0;
        int sizeb = 0;
        ListNode* cura = headA;
        ListNode* curb = headB;
        while(cura != NULL){
            sizea++;
            cura = cura->next;
        }
        while(curb != NULL){
            sizeb++;
            curb = curb->next;
        }
        cura = headA;
        curb = headB;
        if(sizeb > sizea){
            swap(sizea,sizeb);
            swap(cura,curb);
        }
        int cnt = sizea -sizeb;
        while(cnt--){
            cura = cura->next;
        }
        while(cura != NULL){
            if(cura == curb){
                return cura;
            }
            cura = cura->next;
            curb = curb->next;
        }
        return NULL;
    }
};

注意这里直接使用swap()交换两个变量内存地址。

142.环形链表II

看过卡哥的视频后,此题分为两部分:

  • 判断链表是否为环形链表:使用双指针(快慢指针),快指针每次移动两格,满指针每次移动一格,如果为环形,那么快指针会在慢指针在环中未转完一圈的时候与慢指针相遇。
  • 找到环的入口:在这里插入图片描述
    这里直接上卡哥的图!其实不难理解,只要自己模拟一遍就行。

总的处理逻辑就是,首先判断是否为环,如果为环,使两个指针分别在相遇点和head位置同时移动到相遇就是环的入口,直接给出代码:

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;
    }
};

这里外层while循环时也是要注意首先需要判断fast是否为NULL再判断他的next。

在AC完后查看提交记录,发现自己之前用hashmap AC过一次,自己都忘了,代码如下:

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        unordered_set<ListNode *> visited;
        while (head != nullptr) {
            if (visited.count(head)) {
                return head;
            }
            visited.insert(head);
            head = head->next;
        }
        return NULL;
        
    }
};

回忆了一下,就是遍历链表,遍历的时候将结点一个个存入hashmap中,如果遍历结束的话那么就直接返回NULL;如果在遍历过程中发现已经存入,就直接返回这个结点,这里使用unordered_set中的count()函数来查询。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值