代码随想录day4|24.两两交换 ;19. 删除链表的倒数第 N 个结点; 02.07链表相交; 142. 环形链表 II

24.两两交换

24.两两交换|讲解

题目思路

本体的思路与翻转链表的操作是类似的。不同之处在于cur指针每次前进两步。

理解的关键是step1,当我们用指针指向一个节点时,相当于我们(可以)将指向他的箭头删除

实现

点击查看代码
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummyNode=new ListNode(0,head);
        ListNode* cur=dummyNode;
        while(cur->next!=nullptr && cur->next->next != nullptr){
            ListNode* temp = cur->next->next->next;
            ListNode* temp2 = cur->next;
            cur->next = cur->next->next;
            cur->next->next = temp2;
            cur->next->next->next = temp;
            cur = cur->next->next;
        }
        return dummyNode->next;
    }
};

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

题目|文章

题目思路

使用双指针法,快指针比慢指针领先n个位置,当慢指针到达链表底部时,确定倒数第n+1个节点的位置,从而达到目的。

实现

点击查看代码
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyNode = new ListNode(0,head);
        ListNode* slow = dummyNode;
        ListNode* fast = dummyNode;
        while(n--){
            fast = fast->next;
        }
        
        while(fast->next != nullptr){
            fast = fast->next;
            slow = slow->next;
        }
        ListNode* temp = slow->next;
        slow->next = slow->next->next;
        delete temp;
        return dummyNode->next;

    }
};

复杂度分析:

  • 时间复杂度O(n),n为链表的长度
  • 空间复杂度O(1)

其他思路

1.计算链表长度

2.栈

  • 思路:遍历链表的同时将所有节点入栈,根据先进后出原则,弹出第n个节点即可达成目的。
  • 代码实现:
点击查看代码
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyNode = new ListNode(0,head);
        stack<ListNode*> stk;
        ListNode* cur = dummyNode;
        while(cur){
            stk.push(cur);
            cur=cur->next;
        }
        for(int i = 1; i <= n; i++){
            stk.pop();
        }
        cur=stk.top();
        ListNode* temp = cur->next;
        cur->next = cur->next->next;
        delete temp;
        return dummyNode->next;


    }
};
  • 复杂度分析:
    时间复杂度:O(n),n为链表的长度
    空间复杂度:O(n),n为链表的长度,主要来自于stack的开销

02.07链表相交

题目|文章

1.栈

思路

遍历链表的同时将所有节点入栈,通过对比弹出栈的节点是否相同寻找第一个不相同的节点。

实现

点击查看代码
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        stack<ListNode*> stkA;
        stack<ListNode*> stkB;
        ListNode* dummyNodeA = new ListNode(0);
        dummyNodeA->next = headA;
        ListNode* dummyNodeB = new ListNode(0);
        dummyNodeB->next = headB;
        ListNode* curA = dummyNodeA;
        ListNode* curB = dummyNodeB;
        while(curA){
            stkA.push(curA);
            curA = curA->next;
        }
        while(curB){
            stkB.push(curB);
            curB = curB->next;
        }
        while(curA == curB){
            curA = stkA.top();
            curB = stkB.top();
            stkA.pop();
            stkB.pop();
        }
        return curB->next;
    }
};

复杂度分析

  • 时间复杂度:O(n),n为链表的长度
  • 空间复杂度:O(n),n为栈的开销

2.双指针法

142.环形链表II

题目|文章

1.哈希

思路

要查看是否出现过,最直接的方法就是hash。用哈希表记录经过的节点,如果之后遇到此前遍历过的节点,就是环的入口

实现

点击查看代码
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 nullptr;
    }
};

复杂度分析

  • 时间复杂度:O(n),n为链表的长度
  • 空间复杂度:O(n),n为hash的开销

2.快慢指针

思路

  1. slow指针每次走一步,fast每次走两步,最终一定会相遇
  2. 相遇时,fast走的路程f=a+(n+1)b+nc,slow指针走过的路程s=a+(m+1)b+mc,由f=2s可知,a+(n+1)b+nc=2a+2(m+1)b+2mc
    a=(n+1-2m-2)b+(n-2m)c
    a=(n-2m-1)b+(n-2m)c
    a=(n-1)b+nc
    a=(n-1)(b+c)+c
  3. 所以创建temp指针从head出发,slow从相遇点出发,最终会在入口处相遇。

实现

点击查看代码
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast != NULL && fast->next != NULL) {
            slow = slow->next;
            fast = fast->next->next;
            // 快慢指针相遇,此时从head 和 相遇点,同时查找直至相遇
            if (slow == fast) {
                ListNode* index1 = fast;
                ListNode* index2 = head;
                while (index1 != index2) {
                    index1 = index1->next;
                    index2 = index2->next;
                }
                return index2; // 返回环的入口
            }
        }
        return NULL;
    }
};

复杂度分析

  • 时间复杂度:O(n),n为链表的长度
  • 空间复杂度:O(n),n为栈的开销

链表总结

1.链表常规做法包括栈的使用或者双指针的使用。栈的空间复杂度要高一些。
2.对于插入节点,删除结点,交换节点这些基本操作要做到非常熟练

posted @   缩地  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示