24. 两两交换链表中的节点 19.删除链表的倒数第N个节点 面试题 02.07. 链表相交 142.环形链表II

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

实现思路

  1. 定义一个虚拟头结点 head_dummp,初始的 next 指针指向链表的头结点 head。
  2. 定义一个指针变量 p,初始指向虚拟头结点 head_dummp。
  3. 判断 p 指向的节点是否有下一个节点且下一个节点是否有下一个节点,如果没有则退出循环。
  4. 定义两个指针变量 temp1 和 temp2,分别指向 p 指向的节点的下一个节点和 p 指向的节点的下一个节点的下一个节点的下一个节点。
  5. 交换 p 指向的节点的下一个节点和 p 指向的节点的下一个节点的下一个节点。具体操作是:
  6. 将 p 指向的节点的 next 指针指向 p 指向的节点的下一个节点的下一个节点。
  7. 将 p 指向的节点的下一个节点的下一个节点的 next 指针指向 p 指向的节点的下一个节点。
  8. 将 p 指向的节点的下一个节点的 next 指针指向 temp2。
  9. 将 p 指向的节点的 next 指针指向 p 指向的节点的下一个节点的下一个节点。
  10. 重复步骤 3-6,直到 p 指向的节点没有下一个节点或下一个节点没有下一个节点。
while (p->next != nullptr && p->next->next != nullptr)

每次循环的条件是 p 指向的节点有下一个节点且下一个节点有下一个节点。

代码实现

/**
 * 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* swapPairs(ListNode* head) {
        ListNode* head_dummp = new ListNode();
        head_dummp->next = head;
        ListNode*p = head_dummp;
        ListNode*temp1 = nullptr;
        ListNode*temp2 = nullptr;
        while(p->next!=nullptr && p->next->next!=nullptr)
        {
            temp1 = p->next;
            temp2 = p->next->next->next;
            p->next = p->next->next;
            p->next->next = temp1;
            temp1->next = temp2;
            p = p->next->next;
        }
        return head_dummp->next;
    }
};

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

实现思路

本题使用双指针的方法即可,快指针和慢指针相隔n+1个结点,移动速度都为1,这样快指针第一次移动到null的时候,慢指针刚好指向待删除结点的前驱结点q,此时q指向q->next->next即可。注意,力扣上面如果没有特别说明,head结点均是存储数据的,所以可以使用虚拟头节点来解决这个问题。

代码实现

/**
 * 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* dummy_head = new ListNode();
        dummy_head->next = head;
        // 初始化慢指针
        ListNode* q = dummy_head;
        // 初始化快指针
        ListNode* p = dummy_head;
        n+=1;
        while(n--)
            p = p->next;
        // 查找
        while(p!=nullptr)
        {
            p = p->next;
            q = q->next;
        }
        q->next = q->next->next;
        return dummy_head->next;
    }
};

面试题 02.07. 链表相交

实现思路


本题解决方法也是使用双指针的解法,如上图所示,我们分别从a1和b1开始遍历,当遍历完c3时,再接着遍历另外一个链表。

// 第一次循环 无相同
headA:a1+a2+c1+c2+c3+b1+b2+b3
headB:b1+b2+b3+c1+c2+c3+a1+a2

// 第二次循环 c1 相同
headA:c1+c2+c3+a1+a2
headB:c1+c2+c3+b1+b2+b3
       ⬆ 

当循环headA循环b3结束后让指针指向

代码实现

/**
 * 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) {
        if(headA==nullptr || headB==nullptr)
            return nullptr;
        ListNode* p = headA;
        ListNode* q = headB;
        while(p!=q)
        {
            if(p==nullptr)
                p = headB;
            else
                p = p->next;
            if(q==nullptr)
                q = headA;
            else
                q = q->next;
        }
        if(p==q && p==nullptr)
            return nullptr;
        else
            return p;
    }
};

链表相交 142.环形链表II

实现思路

采用floyd算法实现。我们使用 Floyd 算法来检测链表是否有环。使用两个指针 slow 和 fast,初始都指向链表的头节点 head,然后,我们在链表上进行遍历,每次让 slow 指针向前移动一个节点,让 fast 指针向前移动两个节点。当两个指针相遇时,我们就可以确定链表有环。
如果链表无环,则 fast 指针会在遍历结束时变为 nullptr。如果链表有环,我们就使用两个指针(从头开始遍历的指针和从相遇点出发的指针)同时遍历,直到再次相遇。这时,这个相遇的节点即为链表开始入环的第一个节点。

代码实现

/**
 * 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* slow = head;
        ListNode* fast = head;

        while (fast && fast->next) {
            slow = slow->next;
            fast = fast->next->next;
            // 如果链表有环,则 slow 和 fast 会在环内相遇
            if (slow == fast) {
            // 从头开始遍历,并用另一个指针同时从相遇点出发
            // 当两个指针再次相遇时,即为链表开始入环的第一个节点
            ListNode* ptr1 = head;
            ListNode* ptr2 = fast;
            while (ptr1 != ptr2) {
                ptr1 = ptr1->next;
                ptr2 = ptr2->next;
            }
            return ptr1;
            }
        }

        // 如果 fast 为 nullptr,则说明链表无环
        return nullptr;
    }
};
posted @ 2022-12-31 22:47  蠢蛋快跑  阅读(389)  评论(0)    收藏  举报