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

24.两两交换链表中的节点
19.删除链表的倒数第N个节点
面试题 02.07. 链表相交
142.环形链表II
总结

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

第一想法

只是对两个节点进行交换,这个比较好操作,但是两个节点交换后如何根下一个交换后的节点建立联系。制定的规则应该符合第一个交换的节点对,然后也应该符合第二个交换的节点对,所以这个规则肯定是要联系到前一个节点对中的元素,因此要引入一个头节点。

解题思路

1->2->3->4
2->1->4-_3
第一步:dummy->2
第二步:2->1
第三步:1->3
此时为 dummy->2->1->3->4->空
把cur指针指向1重复上述
第一步:1->4
第二步:4->3
第三步:3->空
此事为 dummy->2->1->4->3->空
把cur指针指向3重复上述不满足cur->next或者cur->next->next存在

代码

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        if (!head || !head->next) return head;
        auto dummy = new ListNode(-1);
        dummy->next = head;
        auto cur = dummy;
        while (cur->next != nullptr && cur->next->next != nullptr){
            auto a = cur->next;
            auto b = cur->next->next->next;

            cur->next = cur->next->next;
            cur->next->next = a;
            cur->next->next->next = b;

            cur = cur->next->next;
        }
        return dummy->next;
    }
};

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

第一想法

出现需要删除第一个节点的,一定需要一个虚拟头节点辅助。要判断什么时候结束循环,然后把next指向进行修改。

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        auto dummy = new ListNode(-1);
        dummy->next = head;
        auto cur = head, pre = dummy;
        for (int i = 0; i < n; i ++) cur = cur->next;
        while (cur != nullptr){
            pre = pre->next;
            cur = cur->next;
        }
        pre->next = pre->next->next;
        return dummy->next;
    }
};

面试题 02.07. 链表相交

第一想法

a,b两个ListNode指针分别指向两个头节点,如果谁先到达空节点,则指向另一个头节点,完成一次不同指向后一定能判断是否是相交的,如果不相交则最后会在空节点碰面。

解题思路

  1. 围城一个圈,看是否有交点,同上
  2. 两个链表右端对其,然后从共同的起点开始看是否有相同的节点。

代码

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* a = headA;
        ListNode* b = headB;
        while (a != b){
            if (a != nullptr) a = a->next;
            else a = headB;
            if (b != nullptr) b = b->next;
            else b = headA;
        }
        return a;
    }
};
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        int lenA = 0, lenB= 0;
        auto curA = headA, curB = headB;
        while (curA != nullptr){
            lenA ++;
            curA = curA->next;
        }
        while (curB != nullptr){
            lenB ++;
            curB = curB->next;
        }
        if (lenB > lenA){
            swap(lenB, lenA);
            swap(headA, headB);
        }
        int gap = lenA - lenB;
        while (gap --) headA = headA->next;
        while (headA != headB){
            if (headA) headA = headA->next;
            if (headB) headB = headB->next;
        }
        return headA;
    }
};

142. 环形链表

第一想法

用快慢指针指向头节点,slow = slow->nextfast = fast->next->next,所以slow走了a + b,fast走了a+2b+c的路程,a = c,因此相遇后把其中一个指针指向头节点,然后再次相遇就是环的起始位置。

存在问题

  1. 循环什么时候结束?
    此时用fast != slow来判断是不行的,因为初始化时都指向头节点。
    其中fast指针存在环的话是不会指向空节点的,如果没环的话每次走两格,最后下一个节点是空,或者下下个是空。

代码

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        auto slow = head, fast = head;
        for (; fast != nullptr && fast->next != nullptr;){
            slow = slow->next;
            fast = fast->next->next;
            // cout << fast->val << slow->val << endl;
            if (fast == slow){
                fast = head;
                while (fast != slow){
                    fast = fast->next;
                    slow = slow->next;
                }
                return fast;
            }
        }
        return nullptr;
    }
};

总结

1. 链表基础知识

链表是非连续存储的,增加和删除是O(1),但是查找是o(n)的。

struct ListNode{
	int val;
	ListNode* next;
	ListNode(int x): val(x), next(nullptr) {}
};

2. 题目类型

  1. 链表基本操作:增删改查,会写整个类方法
  2. 对头节点进行操作:虚拟头节点
  3. 反转链表:完全反转和部分反转,对于更改next的顺序和结束条件需要注意
  4. 删除节点:结束条件
  5. 链表相交 有环:方法类似,都是看如果有环第二次转一定有相交的
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值