代码随想录算法训练营第四天|LeetCode24.两两交换链表中的节点,19.删除链表的倒数第N个节点,面试题02.07. 链表相交,142.环形链表II

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

三指针法:对于链表中利用循环结构交换顺序的过程,需要注意各个节点的情况,保证不落下某结点的指针导致无法再找到响应的节点。

我在写代码时尤其是链表操作,往考虑过多比如链表长度奇数偶数分开来考虑导致代码很臃肿,但是其实大多数情况可以保持一致。

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummy_head = new ListNode(0, head);
        ListNode* pre = dummy_head, *curr = head, *temp;
        while(curr != nullptr && curr->next != nullptr) {
            temp = curr->next;
            pre->next = temp;
            curr->next = temp->next;
            temp->next = curr;
            pre = curr;
            curr = curr->next;
        }
        head = dummy_head->next;
        delete dummy_head;
        return head;
    }
};

递归法:

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        if (head == nullptr || head->next == nullptr) return head;

        ListNode* temp = head->next;
        head->next = swapPairs(temp->next);
        temp->next = head;
        return temp;
    }
};

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

双指针法:整体思路很简单,首先让一个快指针从头结点向后前进N步,之后让一个慢指针指向头结点,最后让快指针与慢指针以相同的速度前进,直到快指针指向链表末尾时慢指针也就指向待删除元素。

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummy_head = new ListNode(0, head);
        head = dummy_head;
        while(n > 0) {
            head = head->next;
            n--;
        }
        ListNode* temp = dummy_head;
        while(head->next != nullptr) {
            temp = temp->next;
            head = head->next;
        }
        head = temp->next;
        temp->next = temp->next->next;
        delete head;
        head = dummy_head->next;
        delete dummy_head;
        return head;
    }
};

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

整体思路:①根据两个链表末端指针位置是否相同来判断链表是否相交。②找出两个链表长度相差多少,然后让较长的链表指针先行。③两个链表指针同步更新直到两个指针地址相同。

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* ptrA = headA, *ptrB = headB;
        int idxA = 0, idxB = 0;
        while(ptrA != nullptr && ptrA->next != nullptr) {
            ptrA = ptrA->next;
            idxA++;
        } 
        while(ptrB != nullptr && ptrB->next != nullptr) {
            ptrB = ptrB->next;
            idxB++;
        } 
        if(ptrB != ptrA) return NULL;
        else {
            if(idxA > idxB) {
                idxA = idxA -idxB;
                ptrA = headA;
                ptrB = headB;
            }
            else {
                idxA = idxB - idxA;
                ptrB = headA;
                ptrA = headB;
            }
            while(idxA > 0) {
                ptrA = ptrA->next;
                idxA--;
            }
            while(ptrA != ptrB) {
                ptrA = ptrA->next;
                ptrB = ptrB->next;
            }
            return ptrA;
        }
    }
};

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

流程:①设置一个快指针一次前进两个元素、设置一个慢指针一次前进一个元素,如果快指针到达末端,则链表没有环,如果在运行过程中快指针与慢指针出现相同的情况则链表有环形结构。②在快慢指针相遇的地址继续走下去,同时链表头部指针也向后前进,这两个指针相遇的地址就是环形结构的入口。

疑问:

①为什么快慢指针一定会在环形结构内部相遇?

在进入环形结构之后快指针以1的相对速度来靠近,一定有相遇的时刻。

②在第二步流程中为什么指针相遇的位置就是环形结构的入口?

环外结构的长度为,在进入环状结构之后慢指针走过的长度被快指针追上,慢指针如果继续走下去还有的长度到达环状结构入口。

慢指针走过的长度:

快指针走过的长度: 其中n为快指针在追上慢指针之前绕环形结构的圈数

快指针是慢指针速度的二倍:

推导出的式子意味着链表环外长度等于圈环的长度在加上慢指针到环入口的距离(正向距离)。这就意味着流程②的成立。

③为什么慢指针在第一圈的时间内一定会被追上?

快指针追慢指针的速度是1,慢指针前进的速度也是1,在环形结构中快指针必定在慢指针走一圈所需时间范围内追上慢指针。

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if (head == nullptr) return NULL;

        ListNode* fast = head, *slow = head;
        while(fast->next != nullptr && fast->next->next != nullptr) {
            fast = fast->next->next;
            slow = slow->next;
            if(slow == fast){
                fast = head;
                while(fast != slow) {
                    fast = fast->next;
                    slow = slow->next;
                }
                return slow;
            }
        }
        return NULL;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值