代码随想录训练营第四天|LeetCode 24、19、面试题02.07、142

文章介绍了LeetCode上关于链表的几个经典问题的解法,包括24题的两两交换节点,19题的删除倒数第N个节点,面试题02.07的链表相交以及142题的环形链表II。解题策略涉及设置虚拟头结点、双指针法以及利用哈希表检测环等技巧。
摘要由CSDN通过智能技术生成

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

题目链接:24. 两两交换链表中的节点 - 力扣(LeetCode)

  • 设置虚拟头结点。设置了两个遍历节点pre、cur,未用临时节点

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummynode = new ListNode(0, head);
        ListNode* pre = dummynode;
        ListNode* cur = head;
        while (cur && cur->next) {//交换的是cur和cur->next
            pre->next = cur->next;
            cur->next = cur->next->next;
            pre->next->next = cur;

            pre = cur;
            cur = cur->next;
        }
        return dummynode->next;
    }
};

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

题目链接:19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)

  • 一开始的想法就是将链表遍历两遍:

  • 第一遍遍历确定链表总结点数count,删除倒数第n个结点=正数第(count - n + 1)个结点

  • 第二次遍历就是删除第(m - n + 1)个结点即可

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummynode = new ListNode(0, head);
        ListNode* cur = head;
        int count = 0;
        while (cur) {
            count++;
            cur = cur->next;
        }
        //删除第count-n+1个结点
        int index = count - n + 1;
        if (index <= 0) return head;
        cur = dummynode;
        while (--index) {//找到被删除结点的前一个结点
            cur = cur->next;
        }
        ListNode* tmp = cur->next;
        cur->next = tmp->next;
        delete tmp;
        return dummynode->next;
    }
};
  • 双指针法

  • 设置两个指针——slow和fast,并且让两个指针之间相隔n个结点

  • 同时移动slow和fast,目的是为了fast指向链表结尾的nullptr时,slow刚好指向需被删除结点的前一个位置

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummynode = new ListNode(0, head);
        ListNode* slow = dummynode;
        ListNode* fast = head;
        //目的是让slow和fast之间相隔n个结点
        while (fast && n--) {
            fast = fast->next;
        }
        //fast指向链表结尾的nullptr时,slow指向需被删除结点的前一个位置
        while (fast) {
            slow = slow->next;
            fast = fast->next;
        }
        //删除
        ListNode* tmp = slow->next;
        slow->next = tmp->next;
        delete tmp;
        return dummynode->next;
    }
};

LeetCode 面试题02.07链表相交

题目链接:面试题 02.07. 链表相交 - 力扣(LeetCode)

  • 可能因为是二刷,凭本能而写出了??!!!

  • 让两个链表右对齐:求出节点个数差值;让长链表的指针移动到遍历相交的起始位置

  • 遍历两个链表

class Solution {
public:
    ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
        int countA = 0, countB = 0;
        ListNode* curA = headA;
        ListNode* curB = headB;
        while (curA) {
            countA++;
            curA = curA->next;
        }
        while (curB) {
            countB++;
            curB = curB->next;
        }
        if (countA < countB) {
            swap(headA, headB);
            swap(countA, countB);
        }

        curA = headA;
        int index = countA - countB;
        while (index) {
            curA = curA->next;
        }

        curB = headB;
        while (curA && curB) {
            if (curA == curB) return curA;
            curA = curA->next;
            curB = curB->next;
        }
        return nullptr;
    }
};

LeetCode 142环形链表II

题目链接:142. 环形链表 II - 力扣(LeetCode)

  • 直接用哈希表存储已经遍历过的结点,如果当前遍历节点已经存储在哈希表中则有环

class Solution {
public:
    ListNode* detectCycle(ListNode* head) {
        unordered_set<ListNode*> node;//用哈希表存储已经遍历过结点
        ListNode* cur = head;
        while (cur && node.find(cur) != node.end()) {
            node.insert(cur);
            cur = cur->next;
        }
        return cur == nullptr ? nullptr : cur;//cur为nullptr则说遍历到链表结尾,无环;否则返回环的起始位置
    }
};
  • 双指针法/快慢指针法

  • 若存在环,快慢指针相遇一定在环内

  • 相遇时二者所走路径:2* slow = fast

即为

化简为

这个多遍到底是几遍无所谓,总之就是当slow、fast相遇之后,fast继续走【环外节点数】这些步,一定到达环的起点。

class Solution {
public:
    ListNode* detectCycle(ListNode* head) {
        ListNode* slow = head;
        ListNode* fast = head;
        while (fast && fast->next) {
            //slow每次走一步,fast每次走两步
            slow = slow->next;
            fast = fast->next->next;
            //当slow和fast相遇后,再走环外结点个数就走到换的起始位置了
            if (slow == fast) {
                slow = head;//slow走环外的节点
                while (slow != fast) {
                    slow = slow->next;
                    fast = fast->next;//fast在环内继续走
                }
                return slow;//slow、fast相遇的时候就是环的起点
            }
        }
        return nullptr;
    }
};

链表篇总结

  • 要掌握虚拟头结点的设置、双指针法、(按索引)对链表内节点的增加删除

  • 注意增加和删除时断链的前后顺序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值