2023.06.13算法题打卡

本文介绍了四种关于链表的操作:1)使用双指针交换相邻节点;2)删除链表倒数第N个节点;3)找到两个链表的交点;4)检测和找到环形链表的入口。每种操作都利用了快慢指针或者双指针的策略,确保在遍历一次链表的情况下解决问题。
摘要由CSDN通过智能技术生成

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

力扣链接

思路

正常模拟,使用虚拟头结点,否则每次针对头结点的时候还需单独处理。以下是通过画图来展示

 通过以上三个步骤就能对相邻两节点进行交换(因此交换的前提是确保两个节点是存在的,若只剩余一个节点是不需要交换的)

操作之后,链表如下:

 展开观察

记得还需移动临时节点node 

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode *dummyNode = new ListNode(0);
        ListNode *node = dummyNode;
        dummyNode->next = head;
        while (node->next != NULL && node->next->next != NULL) {
            ListNode *tmp = node->next;
            node->next = node->next->next;
            tmp->next = node->next->next;
            node->next->next = tmp;
            node = tmp;
        }
        return dummyNode->next;
    }
};


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

力扣链接

思路:

要想只需遍历一次就可完成操作,使用双指针,快指针最终指向链表末尾(NULL),慢指针指向待删除节点的上一个节点,因此快指针比慢指针多走 n+1 步。

  • 定义fast指针和slow指针,初始值为虚拟头节点
  •  移动快指针,快指针先走 n+1 步
  • 同时移动快慢指针,直到快指针指向最后一个节点(null) 
  • 删除slow指向的下一个节点 

C++代码如下 

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        // 使用双指针,快指针最后指向空指针,快慢指针相差n个节点,
        ListNode *slow, *fast;
        ListNode *dummyNode = new ListNode(0);
        dummyNode->next = head;
        slow = dummyNode;
        fast = dummyNode;
        n++;
        while(n-- && fast != NULL) {
            fast = fast->next;
        }
        while(fast != NULL) {
            fast = fast->next;
            slow = slow->next;
        }
        ListNode *node = slow->next;
        slow->next = slow->next->next;
        delete(node);
        return dummyNode->next;
    }
};

面试题02.07链表相交

力扣链接

思路:

因为不存在环,因此一旦找到相同节点,代表着该节点之后的所有结点都是相同的,因此两个链表从该节点开始后的节点个数完全一致。

因此两个链表长度的差异出现在第一个相同结点之前,设置两个指针分别指向两个链表,并求出两个链表的长度差值为n,移动长链表的指针n个单位,然后一起移动两个指针,直到这两个指针指向的节点相同,代表着找到相同节点。

/**
 * 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;
        ListNode *nodeA = headA;
        ListNode *nodeB = headB;
        while (nodeA) {
            lenA++;
            nodeA = nodeA->next;
        }
        while (nodeB) {
            lenB++;
            nodeB = nodeB->next;
        }
        nodeA = headA;
        nodeB = headB;
        if (lenA > lenB) {
            int n = lenA - lenB;
            while (n--) {
                nodeA = nodeA->next;
            }
        } else if (lenA < lenB) {
            int n = lenB - lenA;
            while (n--) {
                nodeB = nodeB->next;
            }
        }
        while (nodeA != nodeB && nodeA != NULL) {
            nodeA = nodeA->next;
            nodeB = nodeB->next;
        } 
        return nodeA == NULL ? NULL : nodeA;
    }
};

142.环形链表

力扣链接

思路:

该题考察两个知识点:

  • 判断链表是否有环
  • 如果有环,如何找到这个环的入口

判断链表是否有环:

使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果fast和slow指针相遇则代表这个链表有环。

原因:fast指针一定先进入环中,如果fast和slow指针相遇,一定是在环中相遇的

其次,当fast和slow都在环中后,fast指针相对slow指针快一个节点,近似于fast指针追逐slow指针,一定会相遇。

如果有环,如何找到环入口:

快慢指针相遇,慢指针移动了 (x + y)个节点,快指针移动了 (x + y) + n(z + y) 个节点。快指针移动的节点数量是慢指针的2倍,因此:

2*(x + y)= x + y + n * (z + y )

x + y = n * (z + y )

n = 1时, x = z。因此当快慢指针相遇后,从头结点和相遇节点出发,相遇地方则是环入口。

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *slow = head, *fast = head;
        while (fast != NULL && fast->next != NULL) {
            fast = fast->next->next;
            slow = slow->next;
            if (fast == slow) {
                ListNode *node = head;
                while (node != slow) {
                    node = node->next;
                    slow = slow->next;
                } 
                return node;
            }
        }
        return NULL;
    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值