[代码随想录04]两两链表的交换、删除倒数第N个节点、链表相交、链表带环

 前言

 链表+双指针:双指针就是用来处理题目问题的,无论是判断链表相交还是带环,归根到底我们学的还是数学知识,巧妙用数学知识让我们解题目的速度会更快。代码更优雅

题目链接

24. 两两交换链表中的节点 - 力扣(LeetCode)

19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)

面试题 02.07. 链表相交 - 力扣(LeetCode)

142. 环形链表 II - 力扣(LeetCode)

一、两两交换链表中的节点

思路: 定义一个伪头结点,然后定义快慢指针,快指针指向头,慢指针指向伪头,定义两个临时变量去指向交换的节点,和下一个迭代的节点。判断条件是快指针及其下一个对象不为空。

最后执行交换操作和更新操作。

交换操作分为三步:

①伪头指向2

②2指向1

③1指向3

更新操作:

①慢指针指向2

②快指针指向3

 

//迭代操作,三步走,交换,
    ListNode* swapPairs1(ListNode* head) {
        ListNode* newHead=new ListNode(0,head);//保留伪头
        ListNode* fast=head;
        ListNode* slow=newHead;
        while(fast&&fast->next){
            ListNode* tmp1=fast->next;//交换的下一个
            ListNode* tmp2=tmp1->next;//下一组的第一个
            slow->next=tmp1;//交换第二个,指向哨兵下一个,哨兵->2
            tmp1->next=fast;//交换的下一个,等于原先的2->1
            fast->next=tmp2;//指向下一组的第一个1->4
            //更新操作
            slow=fast;//进入新的交换的哨兵 1
            fast=tmp2;//下一组 4
        }
        return newHead->next;
    }
    //递归的思路
    ListNode* swapPairs(ListNode* head) {
    if (head == nullptr || head->next == nullptr) {
            return head;
        }
        ListNode* node1 = head;
        ListNode* node2 = head->next;
        ListNode* node3 = node2->next;
        node1->next = swapPairs(node3); // 1 指向递归返回的链表头
        node2->next = node1; // 2 指向 1
        return node2; // 返回交换后的链表头节点
    }

二、删除倒数第N个节点

 思路:正向简化,寻找到需要删除的结点,直接亏快指针先走N步,然后快慢一起走,就符合题目说的,倒数的意思

ListNode* removeNthFromEnd(ListNode* head, int n) {
        if(head==nullptr||n<=0) return nullptr;
        ListNode* newHead=new ListNode(0,head);
        ListNode* fast=head;
        ListNode* slow=newHead;
        while(n--)fast=fast->next;//快先走
        while(fast){//快慢一起走
            fast=fast->next;
            slow=slow->next;
        }//执行删除逻辑
        ListNode *tmp=slow->next;
        slow->next=slow->next->next;
        delete tmp;
        return newHead->next;
    }

 

三、链表相交

 思路:如果链表相交,A+B的总路程肯定有相等的节点,这个节点的位置就是相交的位置。

 

 ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode*A =headA,*B=headB;
        while(A!=B){
            A=A!=nullptr?A->next:headB;
            B=B!=nullptr?B->next:headA;
        }
        return A;
    }

四、环形链表

 思路:数学知识鸽巢原理,如果有换,走两步和走一步一定能相遇。接下来只需要判断一下环的入口位置即可。

  • f=2s (快指针每次2步,路程刚好2倍)
  • f = s + nb (相遇时,刚好多走了n圈)

推出:s = nb,从head结点走到入环点需要走 : a + nb, 而slow已经走了nb,那么slow再走a步就是入环点了。

ListNode *detectCycle(ListNode *head) {
        ListNode*fast=head,*slow=head;
        while(true){//得到相遇节点
            if(fast==nullptr||fast->next==nullptr)return nullptr;
            fast=fast->next->next;
            slow=slow->next;
            if(fast==slow)break;
        }//一起走直到再次相遇就是环的入口
        fast=head;
        while(fast!=slow){
            fast=fast->next;
            slow=slow->next;
        }
        return fast;
    }

总结

 学会链表的中的一些数学思想有助于我们在理解链表的基础操作上,处理更加复杂的问题!。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值