算法训练 —— 链表(2)

目录

1. LeetCode24. 两两交换链表中的结点

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

3. LeetCode160.相交链表

4. LeetCode141.环形链表

5. LeetCode142.环形链表II

6. LeetCode138.复制带随机指针的链表 


1. LeetCode24. 两两交换链表中的结点

两两交换链表中的结点 

/*解法1:迭代。。设置虚拟头结点*/
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* res = new ListNode(-1);// 设置一个虚拟头结点
        res->next = head;// 将虚拟头结点指向head,这样方面后面做删除操作
        ListNode* cur = res;
        while(cur->next != nullptr && cur->next->next != nullptr)
        {
            ListNode* tmp = cur->next;// 记录临时节点
            ListNode* tmp1 = cur->next->next->next;

            cur->next = cur->next->next;  // 步骤一
            cur->next->next = tmp;        // 步骤二
            cur->next->next->next = tmp1; // 步骤三

            cur = cur->next->next;// cur移动两位,准备下一轮交换
        }
        return res->next;
    }
};

 

 

/*解法2:递归*/
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        //如果链表结点个数为0或1,这时候直接返回head,不需要交换
        if(head == nullptr || head->next == nullptr) return head;

        ListNode* prev = head;
        ListNode* cur = prev->next;
        ListNode* next = cur->next;

        //交换两个节点
        prev->next = next;
        cur->next = prev;

        //以 1->2->3->4->5->nullptr 为例
        //交换之后为 2->1->3->4->5->nullptr
        //因为head是指向1的,所有递归调用的结果返回给head->next
        head->next = swapPairs(next);
        return cur;
        
    }
};

解法2图解: 

 

//解法3:
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        if(head == nullptr || head->next == nullptr) return head;
        ListNode* newhead = head->next;
        ListNode* tmp = nullptr;
        ListNode* prev = head;
        ListNode* cur = prev->next;
        ListNode* next = cur->next;
        while(prev != nullptr && prev->next != nullptr)
        {
            cur->next = prev;
            prev->next = next;
            if(tmp != nullptr) tmp->next = cur;
            tmp = prev;
            prev = next;
            if(prev != nullptr)cur = prev->next;
            if(cur != nullptr) next = cur->next;
        }
        return newhead;
    }
};

        解法3:是不用虚拟的头结点,直接在原链表交换,是一种不错的思路,但是理解起来不是那么容易,建议上面两种方法的理解,下面是图解过程

 

 

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

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

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        //给链表设置一个虚拟头结点(哨兵结点),有效防止删除正数第一个的情况,避免更新头结点
        ListNode* res = new ListNode(-1);
        res->next = head;
        ListNode* fast = head;
        ListNode* slow = head;
        ListNode* prev = res;
        while(n--)//因为题目中n是有效的,所以我们让快指针先走n步
        {
            fast = fast->next;
        }
        while(fast)//然后fast和slow一起走
        {
            fast = fast->next;
            prev = slow;//一起走之前,先记录一下slow的位置,当fast走到空时,slow一定走到了倒数第n个节点上
            slow = slow->next;
        }
        prev->next = slow->next;
        return res->next;
    }
};

 

3. LeetCode160.相交链表

相交链表 

 

//解法1:
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* pA = headA;
        ListNode* pB = headB;
        //你可以算一算图中的pA走完headA从headB开始走到交点,和pB走完headB从headA开始走到交点距离是一样的
        while(pA != pB)//pA == pB时退出,表明走到了交点
        {
            // pA 将headA链表走完了,就去走headB链表
            pA = pA == nullptr ? headB : pA->next;
            // pB 将headB链表走完了,就去走headA链表
            pB = pB == nullptr ? headA: pB->next;
        }
        return pA;
    }
};

//解法2;
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* tailA = headA;
        ListNode* tailB = headB;
        int lenA = 1;
        while(tailA->next)//计算链表A的长度
        {
            ++lenA;
            tailA = tailA->next;
        }

        int lenB = 1;
        while(tailB->next)//计算链表B的长度
        {
            ++lenB;
            tailB = tailB->next;
        }
   
        if(tailA != tailB)//两个链表都走完了,但是不相等,表明一定没有交点
        {
            return nullptr;
        }
        
        int gap = abs(lenB - lenA);//算出长短链表相差多少
        ListNode* shortlist = headA;
        ListNode* longlist = headB;

        if(lenA > lenB)//这里用来准确确定长、短链表
        {
            shortlist = headB;
            longlist = headA;
        }
        
        while(gap--)//让长链表走差距步
        {
            longlist = longlist->next;
        }

        while(longlist != shortlist)//然后长链表和短链表一起走
        {
            longlist = longlist->next;
            shortlist = shortlist->next;
        }
        return longlist;
    }
};

 

4. LeetCode141.环形链表

环形链表 

思路动图:

 

双指针法:

快指针先走两步,紧接着慢指针走

class Solution {
public:
    bool hasCycle(ListNode *head) {
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast && fast->next)
        {
            fast = fast->next->next;
            slow = slow->next;
            if(fast == slow)
            {
                return true;
            }
        }
        return false;
    }
};

5. LeetCode142.环形链表II

环形链表II 

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast && fast->next)
        {
            fast = fast->next->next;
            slow = slow->next;
            if(fast == slow)
            {
                ListNode* meet = slow;
                while(meet != head)
                {
                    meet = meet->next;
                    head = head->next;
                }
                return head;
            }
            
        }
        return nullptr;
    }
};

6. LeetCode138.复制带随机指针的链表 

 

 

class Solution {
public:
    Node* copyRandomList(Node* head) {
        //1.拷贝源节点并链接
        Node* cur = head;
        while(cur)
        {
            Node* copy = new Node(cur->val);
            copy->next = cur->next;
            cur->next = copy;
            cur = copy->next;
        }
        cur = head;
        //2.根据原节点,处理copy节点的random
        
        while(cur)
        {
            Node* copy = cur->next;
            if(cur->random == nullptr)
            {
                copy->random = nullptr;
            }
            else
            {
                copy->random = cur->random->next;
            }
            cur = copy->next;
        }
        cur = head;

        //3.把拷贝节点解下来,链接成新链表。同时恢复原链表;
        Node* copyhead, *copytail;
        copyhead = copytail = nullptr;
        while(cur)
        {
            Node* copy = cur->next;
            Node* next = copy->next;
            if(copytail == nullptr)
            {
                copyhead = copytail = copy;
            }
            else
            {
                copytail->next = copy;
                copytail = copy;
            }
            cur->next = next;
            cur = next;
        }
        return copyhead;
    }
};

 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

霄沫凡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值