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

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

文档讲解:代码随想录 (programmercarl.com)

视频讲解:帮你把链表细节学清楚! | LeetCode:24. 两两交换链表中的节点_哔哩哔哩_bilibili

状态:没写出来

        想到了用三个指针来实现,但是出错点在于,我把三个指针都写到了while循环的外面,感觉这还好,但是提交之后发现超时了,后来对比了一下代码随想录的代码,发现有两个地方不一样。        

        第一个就是把三个指针都写到了while循环的外面,导致两两交换节点之后,我还要再对定义的指针进行移动的操作,这无疑是增加了工作量; 

        第二个就是while中的判断条件,我写的是tmp!=nullptr,还是同样的道理,移动后还要取值判断,这也增加了代码的工作量。

        虚拟头结点确实好用。

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* tmp = cur->next;
           ListNode* tmp1 = cur->next->next->next;

           cur->next = tmp->next;
           tmp->next = tmp1;
           cur->next->next = tmp;

           cur = cur->next->next;
        }

        return dummyhead->next;
    }
};

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

文档讲解:代码随想录 (programmercarl.com)

视频讲解:链表遍历学清楚! | LeetCode:19.删除链表倒数第N个节点_哔哩哔哩_bilibili

状态:勉强写出

        这道题目卡的时间最久,我一开始的思路是,先求出链表总长度,再用总长度减去n,就可以把问题巧妙地转变为删除链表的第n个节点。

        但是leetcode总是报错runtime error: member access within null pointer of type ‘ListNode‘,上网搜了搜,原因是cur->next = cur->next->next;这句话如果cur->next为空,那么就会有给空指针赋值的风险,所以要加上一句判断 if(cur->next!=nullptr),最终才顺利通过。

        但是不是所有情况都可以用加上一个条件判定的方法来解决呢?

        其实不是,有一篇文章已经有例子和详细清晰的解释,在此不赘述了。

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyhead  = new ListNode();
        dummyhead->next = head;
        ListNode* cur = dummyhead;
        int length = Length(dummyhead);
        for(int i = 1;i<length-n+1;i++){
            cur = cur->next;
        }
        if(cur->next!=nullptr)
        cur->next = cur->next->next;
        return dummyhead->next;
    }

    int Length(ListNode* dummyhead){
        int count = 0;
        ListNode* cur = dummyhead->next;
        while(cur != nullptr){
            ++count;
            cur = cur->next;
        }
        return count;
    }
};

这是仿照代码随想录的方法写的算法,大概思想就是,快指针和慢指针形成一个n+1的区间,当快指针指向空时,慢指针的下一个节点正好就是倒数第n个节点。 

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
      ListNode* dummyhead = new ListNode();
      dummyhead->next = head;
      ListNode* slow = dummyhead;
      ListNode* fast = dummyhead;
      while(fast != nullptr && n!=0){
          --n;
          fast = fast->next;
      }
      fast = fast->next;
      while(fast != nullptr){
          slow = slow->next;
          fast = fast->next;
      }
      slow->next = slow->next->next;
      return dummyhead->next;
    }
};

 面试题 02.07. 链表相交

文档讲解:代码随想录 (programmercarl.com)

视频讲解:没有

状态:用暴力的方法写出来的

这道题用暴力的方法是可以做出来的,指针A每移动一次,就让指针B从头到尾扫描B链表,看看有没有地址重合。 但是时间复杂度太高了。

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* dummyheadA = new ListNode();
        ListNode* dummyheadB = new ListNode();
        dummyheadA->next = headA;
        dummyheadB->next = headB;
        ListNode* curA = dummyheadA;
        ListNode* curB = dummyheadB;
        while(curA->next != nullptr){
            curB = dummyheadB;
            while(curB->next != nullptr){
                if(curB->next == curA->next){
                    ListNode* p = curA->next;
                    return p;
                }
                curB = curB->next;
            }
            curA = curA->next;
        }
        return nullptr;
    }
};

        这个是代码随想录上提供的算法,我仿写了一遍,大概思想就是AB链尾对齐遍历。

        时间复杂度是O(n) ,空间复杂度是O(1)。

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* curA = headA;
        ListNode* curB = headB;
        int lenA = 0;
        int lenB = 0;
        while(curA != nullptr){
            ++lenA;
            curA = curA->next;
        }
        while(curB != nullptr){
            ++lenB;
            curB = curB->next;
        }
        curA = headA;
        curB = headB;

        if(lenB > lenA){
            swap(lenA,lenB);
            swap(curA,curB);
        }
        int gap = lenA-lenB;
        while(curA != nullptr && gap > 0){
            --gap;
            curA = curA->next;
        }
        while(curA != nullptr && curB != nullptr){
            if(curA == curB){
                return curA;
            }
            curA = curA->next;
            curB = curB->next;
        }
        return nullptr;
    }
};

142.环形链表II  

文档讲解:​​​​​​​代码随想录 (programmercarl.com)

视频讲解:把环形链表讲清楚! 如何判断环形链表?如何找到环形链表的入口? LeetCode:142.环形链表II_哔哩哔哩_bilibili

状态:没写出来

         快慢指针的思想,就跟在操场跑步类似,比你跑得快的人超过你一次迟早超过你第二次。

        这道题难就难在运用到了数学的思想,要好好理解。

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast != nullptr && fast->next != nullptr){
            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 nullptr;
    }
};

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值