letcode 分类练习 两两交换链表中的节点 删除链表的倒数第N个节点 链表相交 环形链表II

letcode 分类练习 两两交换链表中的节点 删除链表的倒数第N个节点 链表相交 环形链表II

两两交换链表中的节点

在这里插入图片描述

双指针法解决(slow fast),这里我们用first和second分别暂存一下第一个和第二个节点,可以大大避免出错的可能性

/**
 * 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* dummyhead = new ListNode(-1);
        dummyhead -> next = head;
        ListNode* slow = dummyhead; ListNode* fast = dummyhead -> next;
        if(!fast) return dummyhead -> next;
        while(fast && fast -> next){
            ListNode* post = fast -> next -> next;
            ListNode* second = fast -> next;
            ListNode* fisrt = slow -> next;
            slow -> next = second;
            second -> next = fisrt;
            fisrt -> next = post;
            slow = fisrt;
            fast = post;
        }
        return dummyhead -> next;
    }
};

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

在这里插入图片描述 快慢指针解决,我们用一个虚拟头结点来实现找倒数第一个节点的前驱,遍历while(n–)的时候初始化虚拟头结点即可以找到。
我们先让快节点走n次,然后快节点和慢节点同步走,快节点的下一个节点为空的时候(不然slow->next->next会报空指针异常)慢节点即就是我们要找的倒数第N个节点的前驱

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyhead = new ListNode(-1);
        dummyhead -> next = head;
        ListNode* slow = dummyhead; ListNode* fast = dummyhead;
        while(n--){
            fast = fast -> next;
        }
        while(fast->next){
            fast = fast -> next;
            slow = slow -> next;
        }
        slow -> next = slow -> next -> next;
        return dummyhead -> next;
    }
};

链表相交

在这里插入图片描述A跟B的路径我们让headA和headB都走一遍就可以找到交点了

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        int countA = 1; int countB = 1;
        ListNode* tmpA = headA; ListNode* tmpB = headB;
        while(tmpA && tmpB){
            if(tmpA == tmpB) return tmpA;
            tmpA = tmpA -> next;
            tmpB = tmpB -> next;
            if(tmpA == NULL && countA){
                tmpA = headB;
                countA--;
            }
            if(tmpB == NULL && countB){
                tmpB = headA;
                countB--;
            }
        }
        return NULL;
    }
};

环形链表II

在这里插入图片描述

在这里插入图片描述我们有快指针移动距离为
L f a s t = x + y + n ( z + y ) L_{fast} = x + y+n(z+y) Lfast=x+y+n(z+y)
慢指针移动距离
L s l o w = x + y L_{slow} = x + y Lslow=x+y
又由于
L f a s t = 2 L s l o w ⇒ x + y + n ( z + y ) = 2 ( x + y ) ⇒ x = n ( z + y ) − y L_{fast} = 2 L_{slow} \Rightarrow x + y+n(z+y) = 2(x+y)\Rightarrow x = n(z+y)-y Lfast=2Lslowx+y+n(z+y)=2(x+y)x=n(z+y)y
由于相遇的时候,自然肯定是快指针已经走了至少一圈了,所以
n ≥ 1 n ≥1 n1
所以,我们有
x = ( n − 1 ) ( z + y ) + z n = 1 时 , x = z x = (n-1)(z+y) + z \\n=1时,x=z x=(n1)(z+y)+zn=1,x=z
这个时候我们发现,其实就是从头结点出发,然后另一个节点从相遇点出发,新的相遇点就是我们的入口处

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* dummyhead = new ListNode(-1);
        dummyhead -> next = head;
        ListNode* slow = dummyhead;
        ListNode* fast = dummyhead;
        ListNode* together = NULL;
        // 快慢指针模版写法
        while(fast && fast -> next){
            fast = fast->next-> next;
            slow = slow -> next;
            if(slow == fast){
                together = slow;
                break;
            }
        }
        if(!together) return NULL;
        ListNode* cur = dummyhead;
        while(cur!=together){
            cur = cur -> next;
            together = together -> next;
        }
        return cur;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值