代码随想录Day4 | 链表02-leetcode24、19、面试题02.07、142

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

题目链接:两两交换链表中的节点

思路:双指针p1、p2,分别指向每次需要交换的节点。交换过程为p2的next指向p1,p1的next指向p2的next,还需要注意将p1de前一个指针指向交换后的p2以确保不断链

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        if(head == nullptr || head -> next == nullptr)
            return head;
        else{
            ListNode *p1 = head;
            ListNode *dummy_head = new ListNode(0); // 虚拟头结点
            dummy_head->next = head;
            ListNode *prev = dummy_head; // 虚拟头结点
            while(p1 != nullptr && p1->next != nullptr){
                ListNode *p2 = p1->next;
                if(p2 != nullptr){
                    ListNode *temp = p2->next;
                    prev->next = p2;
                    p1->next = temp;
                    p2->next = p1;
                    prev = p1;
                    p1 = p1->next;
                }else break;
            }
            return dummy_head->next;
        }
        
    }
};

1. 空链 or 只有头结点?

- 直接返回head,无需做任何修改

2. 交换需要记录前驱节点,而头节点无前驱?

- 添加虚拟头节点


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

题目链接:删除链表中的倒数第N个结点

1.暴力解法

算法描述:遍历两次,第一次获取链长,第二次得到待删除结点及其前驱结点。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        // 暴力解法:遍历两遍,第一遍获取链长,第二遍获取删除结点
        int len = 0;//记录链长
        ListNode *dummyhead = new ListNode();
        dummyhead->next = head; // 添加虚拟头结点

        ListNode *cur = head;
        while(cur != nullptr){
            len++;
            cur = cur->next;
        }

        ListNode *prev = dummyhead;
        cur = dummyhead->next;
        for(int index = len - n; index > 0; index--){
            prev = prev->next;
            cur = cur->next;
        }

        prev->next = cur->next;
        delete cur;

        return dummyhead->next;
    }
};

注意可能删除的结点为头结点,因此需要添加虚拟头结点。

2.双指针法

算法描述:使用快慢指针,先将快指针移动n+1步,此时慢指针即为相对于快指针而言的倒数第n个结点的前驱。同步移动快慢指针,当快指针为链尾时,慢指针指向的结点即为待删除结点。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        // 快慢指针
        ListNode *slow, *fast;
        ListNode *dummyhead = new ListNode();
        dummyhead->next = head;
        slow = dummyhead;
        fast = dummyhead;

        while(n-- && fast != nullptr){
            fast = fast->next;
        }
        fast = fast->next;
        while(fast != nullptr){
            slow = slow->next;
            fast = fast->next;
        }
        ListNode *temp = slow->next;
        slow->next = temp->next;
        delete temp;
        return dummyhead->next;
    }
};

面试题02.07-链表相交

题目链接:链表相交

算法描述:(来自官方题解,真的很巧妙~)双指针从A和B的head处开始移动并判断当前指向的指针是否相等,若相等则返回。若某一指针指向了nullptr则指向另一条链的头结点,继续遍历直至找到公共结点。

解释:当某一指针指向nullptr后转向另一条链的头结点 --> AB链若相交,则从某一结点开始之后的所有结点都相等。当某一指针p1 == nullptr时,另一指针p2走过的长度即为短链的长度,此时继续向后遍历,长链的指针p2也为nullptr时转向短链,此时p1指针未遍历的长度即为短链的长度,由于题意(相加后所有的后续结点都相同),因此从短链的起始位置和长链后半段与短链长度相等的位置开始遍历,总能找到相交的结点。若不存在交点,此时p1和p2也会同时为nullptr。

(短链遍历完之后,找到长链对应的长度。继续遍历长链找到与短链剩余长度相等的位置。从该位置向后遍历寻找交点)

 /**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if(headA == nullptr || headB == nullptr)
            return nullptr;
        
        ListNode *p1 = headA;
        ListNode *p2 = headB;
        while(p1 != p2){
            p1 = p1 == nullptr ? headB : p1->next;
            p2 = p2 == nullptr ? headA : p2->next;
        }

        return p2;        
    }
};

142-环形链表II

题目链接:环形链表II

1.快慢指针

算法描述:快指针每次走两步,慢指针每次走一步,若快慢指针相遇则存在环。通过快指针一定比慢指针多走整数倍的环的长度这样的等式关系找到环的入口

(待复习) 代码随想录的视频讲解:视频-环形链表  代码随想录文字讲解:文字-环形链表

2.哈希表

算法描述:遍历链表并检查哈希表中是否存在当前结点,若存在即为链表中环的入口,否则加入哈希表中,直至指针指向nullptr

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        //哈希表
        ListNode *cur = head;
        unordered_set<ListNode*> set;
        while(cur != nullptr){
            if(set.find(cur) != set.end()){
                return cur;
            }
            set.insert(cur);
            cur = cur->next;
        }
        return cur;
    }
};

Day5休息日~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值