代码随想录算法训练营Day04|24. 两两交换链表中的节点、19. 删除链表的倒数第 N 个结点、02.07.链表相交、142. 环形链表 II

代码随想录算法训练营Day04|24. 两两交换链表中的节点、19. 删除链表的倒数第 N 个结点、02.07.链表相交、142. 环形链表 II

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

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

首先题干要求相邻两两交换,这里首先涉及到的是对奇偶链表长度如何判断:

  • 奇偶判断:链表长度的奇偶是否需要进行区分。如果区分的话:偶数正常两两交换即可;奇数则只考虑前n-1个节点的交换问题。

  • 虚拟头结点:还是建议设置虚拟头结点,统一所有链表节点的操作

本题主要是考察代码执行流程是否清晰,重点在于画图理清节点变换流程,流程如下:

image-20221119225356738

按照图示步骤,我们需要记录两个临时变量(以图中的1、2节点为例):

  • 设置变量temp1记录1的位置
  • 设置变量temp2记录3的位置

不需要记录2的位置是因为,当执行第一个步骤cur->next = cur->next->next时,变换后我们仍然可以通过cur->next来访问2节点。如果步骤间的顺序打乱,可能会需要更多的临时变量,造成额外的存储开销。

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

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

本题的难点在于如何确定倒数第n个节点,因为在遍历到末尾节点之前,不清楚剩余节点的个数,很容易联想到快慢指针的方式。另外本题有要求给出的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* dummyHead = new ListNode(0);
        dummyHead->next = head;
        ListNode* fast = dummyHead;
        ListNode* slow = dummyHead;
        while (n--) {
            fast = fast->next;
        }
        while (fast->next != nullptr) {
            fast = fast->next;
            slow = slow->next;
        }
        // 此时要删除的节点就是slow的下位节点
        ListNode* temp = slow->next;
        slow->next = slow->next->next;
        delete temp;
        return dummyHead->next;
    }
};

02.07.链表相交

题目链接:面试题 02.07. 链表相交

本题题干的信息比较多:

  • 链表必须保持其原始结构:也就是说明不能使用反转链表的方式进行判断
  • 链表相交的理解:交点不是数值相等,而是指针相等。从首位相交节点后所有链表节点值都相等,但值相等的节点可能也不是相交节点。
  • 需要有异常处理:如果两链表没有相交,则返回相交节点值为0

本题的关键在于对齐如何让两个链表遍历指针分别到其末尾节点的链表长度相等。我们求出两个链表的长度,并求出两个链表长度的差值,然后让curA移动到,和curB 末尾对齐的位置。此时我们就可以比较curAcurB是否相同,如果不相同,同时向后移动curAcurB:

  • 如果遇到curA == curB,则找到交点。

  • 否则循环退出返回空指针。

代码如下:

/**
 * 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) {
        int lenA = 0, lenB = 0, diff;
        ListNode* curA = headA;
        ListNode* curB = headB;
        while (curA != NULL) {
            lenA++;
            curA = curA->next;
        }
        while (curB != NULL) {
            lenB++;
            curB = curB->next;
        }
        //比较前重置链表长度较短的头指针位置
        if (lenA - lenB >= 0) {
            diff = lenA - lenB;
            cout << diff << endl;
            curA = headA;
            while (diff--) {
                curA = curA->next;
            }
            curB = headB;
        }
        else {
            diff = lenB - lenA;
            cout << diff << endl;
            curB = headB;
            while (diff--) {
                curB = curB->next;
            }
            curA = headA;
        }
        
        
        
        while (curA != NULL && curB != NULL) {
            if (curA == curB)
                return curA;
            curA = curA->next;
            curB = curB->next;
        }
        return 0;
    }
};

代码中需要注意的是,不确定A、B哪个链表是较长的,所以需要对lenA-lenB进行判断,当把较长的链表移动的对齐位置时,记得重置因为遍历链表长度而移动的另一链表指针。

当然,也可以默认lenA为较长链表的指针,如果lenB链表长度更大,我们对其进行一个转换即可,这样可能更好地提高代码的可读性和整洁性。

142. 环形链表 II(⭐️)

题目链接:142. 环形链表 II

涉及数学公式的推导。具体可以参考卡哥的博客内容,写的已经非常详细和透彻了142.环形链表II题解思路

简单来说,就是采用快慢指针的方式从头指针开始分别采用步长两个节点、一个节点去遍历链表,如果有环则**两个节点必然在环中某处相遇,而头指针跟相遇点距离链表进入环的起点是相同距离的。****

代码如下:

/**
 * 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* fast = head;
        ListNode* slow = head;
        bool isCircle = false;
        while (fast != NULL && fast->next != NULL && fast->next->next != NULL) {
            fast = fast->next->next;
            slow = slow->next;
            if (fast == slow) {
                isCircle = true;
                break;
            }
        }
        if (!isCircle)
            return nullptr;
        slow = head;
        while(fast != slow) {
            fast = fast->next;
            slow = slow->next;
        } 
        return fast;
    }
};
posted @ 2022-11-19 23:11  脱线森林`  阅读(2259)  评论(0编辑  收藏  举报