代码随想录day4 链表进阶

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

题目

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

示例 1:

代码随想录day4 链表进阶_第1张图片

输入:head = [1,2,3,4]
输出:[2,1,4,3]

思考

本题基本思路是隔两步执行一次交换的操作,操作的方法可以是交换数值或者交换指针,对于交换数值来说,其实就是swap(a,b);对于交换指针来说,需要使用虚拟头结点的方法,因为需要知道要交换元素的前一个元素是啥,继而连接到其下一个元素,另外,按照图中所示,当虚拟头结点连接到2前,要把1、3都保存下来,因为链路会断。

代码

//  交换数值法

class Solution {

public:

    ListNode *swapPairs(ListNode *head)

    {

        if (head == nullptr || head->next == nullptr)

            return head;

        int tmp = 0, pos = 0;

        ListNode *cur = head;

        while (cur != nullptr && cur->next != nullptr) {

            if (pos % 2 == 0) {

                tmp = cur->val;

                cur->val = cur->next->val;

                cur->next->val = tmp;

            }

            cur = cur->next;

            pos++;

        }

        return head;

    }

};

// 交换指针法

class Solution {

public:

    ListNode *swapPairs(ListNode *head)

    {

        ListNode *dummyHead = new ListNode(0);

        dummyHead->next = head;

        ListNode *cur = dummyHead;

        while (cur->next != nullptr && cur->next->next != nullptr) {

            ListNode *tmp1 = cur->next;  // 以示例一为例,要把1,3的node给先存下来,因为链路会断

            ListNode *tmp2 = cur->next->next->next;

            cur->next = cur->next->next;

            cur->next->next = tmp1;

            cur->next->next->next = tmp2;  // 以示例一为例,要摆成2-1-3的阵型

            cur = cur->next->next;         // 每一步要挪两格

        }

        return dummyHead->next;

    }

};

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

题目

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

示例 1:

代码随想录day4 链表进阶_第2张图片

输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5]

思考

初看题目,第一步想的是翻转链表,然后用n--找到对应元素删除,接着再翻转回来,这样做太麻烦,看到讲解视频后发现快慢指针的方法非常巧妙,核心就是利用慢指针比快指针慢n步的思想,将快慢指针同时遍历,当快指针到链表尾部时,慢指针就到了位置n,这里还添加了虚拟头结点,感觉以后遇到找链表倒数位置的题目都可以用这种方法,总结步骤如下:

1、定义快慢指针和虚拟头结点,都从虚拟头结点开始

2、快指针先走n+1步,因为如果要删除元素的必须找到其上一个节点(慢指针)

3、遍历,快慢指针同时移动,当快指针==null时结束

4、删除元素,最稳妥的方式是用 tmp = 该节点,然后删除tmp

代码

class Solution {

public:

    ListNode *removeNthFromEnd(ListNode *head, int n)

    {

        ListNode *dummyHead = new ListNode(0);

        dummyHead->next = head;

        ListNode *fast = dummyHead;

        ListNode *slow = dummyHead;  // 快指针先走n步,然后快慢指针一起走,当快指针指向nullptr时,慢指针指向倒数第n个节点

        n++;  // 要让slow等于相对应节点的前一个节点

        while (n-- && fast != nullptr)

            fast = fast->next;

        while (fast != nullptr) {

            fast = fast->next;

            slow = slow->next;

        }

        ListNode *tmp = slow->next;

        slow->next = slow->next->next;

        delete tmp;

        tmp = nullptr;

        return dummyHead->next;

    }

};

160 链表相交

题目

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

示例 1:

代码随想录day4 链表进阶_第3张图片

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at '8'

思考

最初想用循环两个链表暴力解,看完讲解视频后发现可以先将两个链表的长度求出来,然后把长链表的head并其短链表的head,接着head一起移动,当两个链表指针相等时则返回(注意,必须是指针相等而非数值相等),且必须先判断是否两个是否相等再移动

代码

// 移动指针解

class Solution {

public:

    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB)

    {

        ListNode *countA = headA;

        ListNode *curA = headA;

        ListNode *countB = headB;

        ListNode *curB = headB;

        int sizeA = 0, sizeB = 0;

        // 计算headA和headB长度

        while (countA != NULL) {

            countA = countA->next;

            sizeA++;

        }

        while (countB != NULL) {

            countB = countB->next;

            sizeB++;

        }

        if (sizeA >= sizeB) {

            int minA = sizeA - sizeB;

            while (minA--)

                curA = curA->next;  // 如果headA长度大于B,则把headA移动懂和B末尾对齐的位置

            while (curA != NULL) {

                if (curA == curB)

                    return curA;  // 注意,这里是指针相等而不是数值相等

                curA = curA->next;

                curB = curB->next;

            }

        } else {

            int minB = sizeB - sizeA;

            while (minB--)

                curB = curB->next;  // 同上,headB大于A的操作

            while (curB != NULL) {

                if (curB == curA)

                    return curB;

                curA = curA->next;

                curB = curB->next;

            }

        }

        return NULL;

    }

};

// 暴力解

class Solution {

public:

    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB)

    {

        ListNode *cur = headA;

        while (cur != NULL) {

            ListNode *cur1 = headB;

            while (cur1 != NULL) {

                if (cur == cur1)

                    return cur1;  // 注意,必须是指针相等而不是数字相等

                cur1 = cur1->next;

            }

            cur = cur->next;

        }

        return NULL;

    }

};

142.环形链表II

题目

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

为了表示给定链表中的环,使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

说明:不允许修改给定的链表。

示例 1:

代码随想录day4 链表进阶_第4张图片

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点,即元素2

思考

这题是完全懵了,没有任何思路,看完讲解视频后发现需要用快慢指针,核心是一个数学表达式,下面列出分析步骤:
1、设置快慢指针,快指针每次走两步,慢指针每次走一步,这样快指针只比慢指针多走一步,保证在套圈是不至于遗漏慢指针

2、设从头结点出发到环起点长度为x,在环内两指针时相遇长度为y,环内从相遇位置到环起点位置为z,如下图

代码随想录day4 链表进阶_第5张图片

3、可以得出,相遇时慢指针走过的路程为x+y,快指针走过的路程为x+y+n(y+z)(因为快指针可能在环里走了n圈),又因为快指针速度是慢指针两倍,则路程也是两倍,即:

2(x+y) = x +y+n(y+z) -> x = n (y + z) - y -> x = (n - 1) (y + z) + z

从上述等式中可以看出,x比z多了n-1个环的路程,也就是说,从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是环形入口的节点,那么在两指针相遇时可以设pos1 = head; pos2 = 相遇时节点,pos1和pos2再相遇时就是环的入口

代码

class Solution {

public:

    ListNode *detectCycle(ListNode *head)

    {

        ListNode *fast = head;

        ListNode *slow = head;

        while (fast != NULL && fast->next != NULL) {

            fast = fast->next->next;

            slow = slow->next;  // 快指针走两步,慢指针走一步,这样快比慢每次只多一步,在套圈的过程中不会漏掉慢指针

            if (fast == slow) {  // 如果快慢指针相等,证明有环

                ListNode *pos1 = fast;

                ListNode *pos2 = head;

                while (pos1 != pos2) {

                    pos1 = pos1->next;

                    pos2 = pos2->next;

                }  // 有环证明从起点和快慢指针相遇的位置同时出发一定能再次相遇,这时相遇点就是环的起点

                return pos1;

            }

        }

        return NULL;

    }

};

你可能感兴趣的:(链表,数据结构,算法)