代码随想录day6-链表(2)

代码随想录day6-链表(2)

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

题目分析:
从分析的角度确实不够严谨,这个题就是典型的双指针的题目。要求删除倒数的第N个结点,我们设置一个先后指针,先指针从正数第N+1个结点出发,后指针从dummyHead出发,这样,当先指针到达nullptr的时候,后指针正好可以到达需要删除的前一个结点地方,二者中间有N个结点,也就达到了删除倒数第N个结点的目的。注意这里好好理解这个N+1以及虚拟结点。

题目解答:

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyHead = new ListNode(0, head);
        ListNode* behind = dummyHead;  // 后结点
        ListNode* front = head;  // 前结点
        while(n-- && front) {
            front = front->next;
        }
        // 此时front指向的就是第n+1个结点
        while (front) {
            front = front->next;
            behind = behind->next;
        }
        // 此时behind就是需要删除的结点的前一个结点
        ListNode* temp = behind->next;
        behind->next = behind->next->next;
        ListNode* ans = dummyHead->next;
        delete temp;
        delete dummyHead;
        return ans;
    }
};

2、LeetCode 160 链表相交

题目分析:
本题最简单的思路就是分别遍历两个链表,获得两个链表的长度,然后将两个链表按照尾巴对齐,然后从短的头部进行遍历,就能得到链表相交的起始结点。

题目解答:

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* curA = headA;
        ListNode* curB = headB;
        int lenA = 0;
        int lenB = 0;
        // 分别获取链表的长度
        while (curA) {
            lenA++;
            curA = curA->next;
        }
        while (curB) {
            lenB++;
            curB = curB->next;
        }

        // 将二者按照尾巴对齐,起始就是长的链表的第一个指针移动一下
        curA = headA;
        curB = headB;  // 让指针重新指到头结点
        if (lenA < lenB) {
            swap(curA, curB);
            swap(lenA, lenB);  // 这个操作就相当于是,长的链表就是curA,短的链表就是curB
        }
        for (int i = 0 ; i < lenA - lenB; i++) {
            curA = curA->next;  // 长的第一个结点进行移动,保证跟短的一样长
        }    
        // 二者同时遍历
        for (int i = 0; i < lenB; i++) {
            if (curA == curB) {
                return curB;
            }
            else {
                curA = curA->next;  // 二者同步增加
                curB = curB->next;
            }
        }
        return nullptr;
    }
};

注意这里使用swap函数,将链表以及链表的长度都进行交换,使得长的链表始终为curA所指向的链表。

3、LeetCode 142 环形链表Ⅱ

题目分析:
这个题也是链表中双指针的典型应用,一开始根本不太会,直接看的卡尔的解答,思想非常重要。
主要有一个数学上的推导,可以让思路变得很简单。
首先我们设置两个指针,一个快指针,一个慢指针。快指针每次移动两个,慢指针每次移动一个,这样能保证二者一旦同时进入环中,二者的相对速度是1,快指针总能追上慢指针。
在这里插入图片描述
根据上述的图,可以列出等式:
2*(x+y) = x+y+n(y+z),其中n是快指针在环内转的圈数,整理一下得到:
x = (n-1)(y+z)+z,这个式子表明:一旦存在环,那么x也就是环入口点一定等于相遇点加n-1个环那么长。知道了这一点之后,就可以开始写代码了。

题目解答:

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* fast = head;
        ListNode* slow = head;
        // fast指针每次移动两个,slow指针每次移动一个
        while (fast && fast->next) {
            fast = fast->next->next;
            slow = slow->next;
            if (fast == slow) {  // 代表存在环
                ListNode* index1 = head;
                ListNode* index2 = fast;
                while (index1 != index2) {
                    index1 = index1->next;
                    index2 = index2->next;
                }
                return index1;
            }
        }  
        return nullptr;
    }
};

如果这个题目追问一下环的长度呢?
当fast==slow代表有环,然后fast和slow继续指向next,然后知道下一次相遇,slow走过的正好就是一圈,因为fast相当于走了两圈,正好追上。
**总结:**这两天关于链表的题目稍微做了一些,有一点儿初步的感觉,主要两个点就是双指针以及虚拟头结点,等一刷完成后,再做做这些题,顺便扩展一下其他的题目。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值