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

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

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

代码随想录(programmercral.com)

帮你把链表细节学清楚! | LeetCode:24. 两两交换链表中的节点

思路

只需要搞清楚当前操纵的是那个节点,理清楚什么时候该退出循环(当p的下个节点为空时,说明全部都交换完了),同时因为是两个节点两个节点处理的,所以链表节点个数为奇数的话,需要做一些单独的处理,即要最后一个节点插在处理完的链表尾。

代码实现:

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        //尝试用两个指针交替插入头节点
        ListNode* dummyhead=new ListNode(0);
        ListNode* p=head;
        if(head==nullptr||head->next==nullptr) return head;
        ListNode* rear=dummyhead;//插入链表的尾指针
        rear->next=nullptr;
        while(p!=nullptr&&p->next!=nullptr){
            ListNode* temp=p->next->next;
            p->next->next=rear->next;
            rear->next=p->next;
            rear=p->next;
            
            p->next=rear->next;
            rear->next=p;
            rear=p;//插入节点
            
            p=temp;//移动节点指针
        }
        if(p!=nullptr){//如果是奇数个节点,最后一个节点需要单独处理,因为p->next为空的时候也会跳出循环,也就是循环相当于两个节点两个节点的处理,如果有奇数个节点,最后肯定会漏掉一个未处理,所以要单独处理。
            p->next=rear->next;
            rear->next=p;
            rear=p;
        }
        head=dummyhead->next;
        delete dummyhead;
        return head;
    }
};

时间复杂度o(n) 空间复杂度o(1)相当于对n个节点都进行了一次操作,所以时间复杂度是o(n)

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

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

代码随想录(programmercral.com)

链表遍历学清楚! | LeetCode:19.删除链表倒数第N个节点

方法一

直接求出链表长度,然后算出来倒数第n个元素是正树的第几个元素

代码实现:

class Solution {
public:
    int getlen(ListNode* head){
        ListNode* p=head;
        int count=0;
        while(p!=nullptr){
            count++;
            p=p->next;
        }
        return count;
    }
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        //方法一,
        int length = getlen(head);
        int index = length-n;
        ListNode* dummyhead=new ListNode(0);
        dummyhead->next=head;
        //找到待删除元素的位置
        ListNode* cur = dummyhead;
        for(int i=0;i<index;i++){
            cur=cur->next;
        }
        //删除元素
        ListNode* q=cur->next;
        cur->next=q->next;
        delete q;
        head=dummyhead->next;
        delete dummyhead;
        return head;
    }
};

时间复杂度o(n)空间复杂度o(1)

方法二

双指针法,因为要找倒数第N个节点,所以可以先让快指针移动N个节点,然后快慢指针同时移动,若快指针指向空,这时慢指针指向的节点即为待删除节点。但是由于删除节点需要该节点的前驱节点,所以可以判断快指针的下一个节点是否为空,如果下一个节点为空,那么慢指针指向的便是待删除元素的前驱节点,只需要进行常规的删除操作即可。

代码实现:

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;//先让快指针移动n个节点
        while(fast->next!=nullptr){
            fast=fast->next;
            slow=slow->next;
        }
        //这时慢指针指向待删除元素的前驱节点,接下来进行删除操作
        ListNode* q=slow->next;
        slow->next=q->next;
        delete q;
        head=dummyhead->next;
        delete dummyhead;
        return head;
    }
};

时间复杂度o(n)空间复杂度o(1)

面试题02.07.链表相交

面试题02.07.链表相交

代码随想录(programmercral.com)

思路

要求相交的位置,所以如果两个链表相交,则从后往前数到相交位置的节点个数一定相同,所以两个链表的长度差从哪里产生? 肯定是相交之前的位置,所以只要求得两个链表的长度,长链表先遍历长度差个节点,然后短链表开始与长链表同时遍历,每遍历一个节点判断此时两个链表所指节点是否为同一个节点,如果是,那么返回,如果不是,那就两个链表没有相交节点。

代码实现:

class Solution {
public:
    int getlen(ListNode *head){
        ListNode *p=head;
        int count=0;
        while(p!=nullptr){
            p=p->next;
            count++;
        }
        return count;
    }
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        int lenA=getlen(headA);
        int lenB=getlen(headB);
        ListNode* pa=headA;
        ListNode* pb=headB;
        ListNode* res=nullptr;
        if(lenA>lenB){
            int cha=lenA-lenB;
            while(cha--) pa=pa->next;
            while(lenB--){
                if(pa==pb) {
                    res=pb;
                    break;
                }
                pa=pa->next;
                pb=pb->next;
            }
        }
        else{
            int cha=lenB-lenA;
            while(cha--)pb=pb->next;
            while(lenA--){
                if(pa==pb) {
                    res=pa;
                    break;
                }
                pa=pa->next;
                pb=pb->next;
            }
        }
        return res;
    }

时间复杂度o(n),空间复杂度o(1);

142.环形链表

142.环形链表

代码随想录(programmercral.com)

把环形链表讲清楚! 如何判断环形链表?如何找到环形链表的入口? LeetCode:142.环形链表

思路:

d47dbf332a81490fb9bb8dff9d9084fa.png

如图, 定义快指针fast和慢指针slow,快指针每次跳两格,慢指针每次跳一格。所以如果链表有环的话一定是快指针先进入环,然后慢指针后进入环。
假设从表头到环入口处的距离为x,从入口处到相交的距离为y,从相交处到入口处的距离为z。
那么当快慢指针相交时,便可以根据快慢移动速度的不同列出两个等式(快慢指针各移动了多少距离):
慢:slow=x+y
快:fast=x+y+n(y+z)n代表快指针已经转了n圈了
因为2*慢=快
所以 2(x+y)=x+y+n(y+z)
要找环的入口,所以要找x和yz的对应关系,化解等式得x=n(y+z)-y,因为快指针和慢指针相遇的时候肯定在环里转过1圈以上了(至于为什么可以理解为慢指针被快指针套圈了,套圈意味着他肯定以及跑了一圈以上了),n又代表快指针转了多少圈,所以可以让快指针让出来一圈得到
x=(n-1)(y+z)+z
假设n为1时,x=z(n!=1其实也一样,只不过是快指针多转了几圈,然后最后一圈和n等于一一摸一样)这时就找到了x和z的关系,即相遇节点之后到环入口处的距离和表头到环入口处的距离一样

此外:

2847cc6eaa044d71a53c0936f5585f31.png

 至于为什么慢指针入环第一圈就会被快指针追上,从上图便可以理解,从慢指针入环到相遇这个期间,快指针肯定会遇到慢指针,因为快指针的速度是慢的两倍。

代码实现:

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *slow=head;
        ListNode *fast=head;
        while(fast!=nullptr&&fast->next!=nullptr){
            fast=fast->next->next;
            slow=slow->next;
            if(slow==fast){//快慢指针相遇,此时从head和相遇点同时查找,因为距离一样
                ListNode* index1=fast;
                ListNode* index2=head;
                while(index1!=index2){
                    index1=index1->next;
                    index2=index2->next;
                }
                return index1;
            }
        }
        return nullptr;
    }

总结

今天的第四题难度较大,涉及了数学推理,需要好好掌握,前面三题算是对知识点的巩固。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值