代码随想录算法训练营第四天| 链表

Posted by Zhuoqun on January 13, 2023

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

这道题也太绕了,本身倒是不难,我也差点写出来了。这回倒是想起来先创建dummy_head来操作了。可还是没写出来,这道题还得练几遍。链表的题的确是需要画图才能想清楚一些。

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummy_head = new ListNode(-1, head);
        ListNode* cur = dummy_head;
        
        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;
        }
        
        return dummy_head->next;
        
    }
};

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

虽然是用的笨办法,但是还是一次就做出来啦!还是很开心的。

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummy_head = new ListNode(-1, head);
        ListNode* cur = dummy_head;
        int size = 1;
        while(cur->next != nullptr){
            cur = cur->next;
            size++;
        }
        
        cur = dummy_head;
        int step = size - n;
        while(--step){
            cur = cur->next;
        }
        if(n!=1){
            cur->next = cur->next->next;
        }
        else{
            cur->next = nullptr;
        }
        
        return dummy_head->next;
    }
};

在做笨办法之前,考虑过只遍历一次的话,该怎么写但是没想出来。把笨方法写出来之后,有了信心,一口气也把遍历一次链表的方法完全自己的写出来了。写之前在纸上画了好几个案例,发现用图的话,的确是会思路清晰很多。

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummy_head = new ListNode(-1, head);
        ListNode* cur = dummy_head;
        while(n>0){
            cur = cur->next;
            n--;
        }
        ListNode* pre = dummy_head;
        
        while(cur->next!=nullptr){
            pre = pre->next;
            cur = cur->next;
        }
        if(n == 1){
            pre->next = nullptr;
        }
        else{
           pre->next = pre->next->next; 
        }      
        
        return dummy_head->next;
    }
};

面试题 02.07. 链表相交

多亏了做题前看了今日安排里的题目提示,提醒了我两个链表光是数值一样那不一定就是相交的点,必须是node一样才行。我的想法就是用hashset来储存一个链表的所有点,然后再遍历第二个链表。可行是可行,就是用了太多资源了。(Runtime: 64 ms Memory Usage: 17.3 MB)

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* result = nullptr;
        ListNode* a_ptr = headA;
        unordered_set<ListNode*> uset;

        while(a_ptr != nullptr){
            uset.insert(a_ptr);
            if(a_ptr->next != nullptr)
                a_ptr = a_ptr->next;
            else
                a_ptr = nullptr;
        }

        ListNode* b_ptr = headB;
        while(b_ptr != nullptr){
            auto it = uset.find(b_ptr);
            if(it != uset.end())
                return b_ptr;
            else
            {
                if(b_ptr->next != nullptr)
                    b_ptr = b_ptr->next;
                else
                    b_ptr = nullptr;
            }
        }

        return result;
    }
};

写完后看了Carl的解析。他是利用了两个链表一旦相交了,那么他们所相交的部分肯定是一样长的,不存在又分开的情况。所以,先求出两个链表的长度,然后把短的链表的尾部挪到和长链表平齐,然后两个指针分别指向两个链表,如果两个指针的node不同,那么就一起后移一位。这么做的确是聪明。

142.环形链表II

这一题我同样用的是哈希表来储存经历过的node,然后一旦遇到哈希表里已有的node,那么就说明这个node是环形链表的头。

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* res = nullptr;
        ListNode* cur = head;
        unordered_set<ListNode*> uset;
        
        while(cur != nullptr){
            auto it = uset.find(cur);
            
            if(it != uset.end()){
                res = cur;
                break;
            }
            else{
                uset.insert(cur);
                cur = cur->next;
            }
        }
        return res;
    }
};

这道题用双指针的写法,还是有些糊涂,需要多看几遍。