反转链表2,穿针引线法

题目链接92. 反转链表 II - 力扣(LeetCode)

这次属于题目优化的思路

常规思路就是切断链表,然后进行整个反转操作,这里面就只需要注意链表的节点获取问题

而穿针引线的方法只需要遍历一次链表,比较考验对链表操作的理解,多指针的情况下,很容易造成线断掉的情况

细节如下

/**
 * 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:

    //利用链表的切割来做来着
    //找到切割链表的点大概是,链表的left的前一个和right的后一个

    void reverse(ListNode* head){
        ListNode *pre=nullptr;
        ListNode *cur=head;
        ListNode *temp;
        while(cur!=nullptr){
            //temp要在里面一开始定义,避免发生,temp在最后cur->next最后出现空指针异常的情况
            temp=cur->next;
            cur->next=pre;
            pre=cur;
            cur=temp;
        }

    }
    ListNode* reverseBetween(ListNode* head, int left, int right) {

        //定义虚拟头结点,避免讨论
        ListNode* dummyHead=new ListNode(-1);
        dummyHead->next=head;
        //1.找到需要翻转链表的范围
        ListNode *Left;
        ListNode *Right;
        int cntleft=0;
        int cntright=0;
        //定义一个节点指针
        ListNode *cur=dummyHead;
        ListNode* pre;

        //就是问题所在你需要找到的其实是链表left的前一个节点,以及right节点,所以说要注意范围
        while(cntleft!=left-1){
            cur=cur->next;
            cntleft++;
            cntright++;
        }

        pre=cur;
        //好像没啥用left=pre->next;

        while(cntright!=right){
            cur=cur->next;
            cntright++;
        }
        Right=cur;


        //2.开始穿针
        ListNode *after=pre->next;
        cur=after->next;
      for(int i=1;i<=right-left;i++){
            after->next=cur->next;
            cur->next=pre->next;
            pre->next=cur;
            cur=after->next;
    }
        

        return dummyHead->next;

        







      

    }
};

注意的是指针一般不能按来做比较,因为指向的是地址

并且一定注意操作次数以及空指针的问题

知道操作次数,最好还是用for循环比较好拉

也并不是,因为,其实是right的值在最后改变了

所以链表一定要尤其注意空指针的问题

在链表的节点改变之后,相应的会引发一系列连锁反应

双指针法的应用

/**
 * 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 *dummyHead=new ListNode(-1);
        dummyHead->next=head;
        //本题采用双指针的方法,采用快慢指针的思路进行操作
        //先让快指针运动n次再让慢指针动,直到慢指针运动到结尾就可以
        ListNode* fast=dummyHead;
        ListNode* slow=dummyHead;
        while(n--){
            fast=fast->next;
        }

        while(fast!=NULL&&fast->next!=NULL){
            fast=fast->next;
            slow=slow->next;
        }

        slow->next=slow->next->next;
        return dummyHead->next;

    }
};

小心空指针就可以

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值