92. 反转链表 ||

 题目:

给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。

示例 1:


输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]
示例 2:

输入:head = [5], left = 1, right = 1
输出:[5]
 

思路:
类似于这种链表题,其实很好的一个习惯要先自己在纸上模拟过程,对于写代码有很好的思路指引过程。做过反转全部链表的小伙伴应该有印象,反转全部链表我们的办法,可以用到双指针迭代,可以用递归。举一反三我们这里反转局部链表呢。再用递归的话是否又有问题呢。答案是肯定的。因为,如果在不存储前驱结点,后置结点的情况下,直接一遍遍历,递归的话,肯定会把前驱和后置结点一起反转,所以我们如果硬是要用递归的话,就只能在局部反转的时候用递归。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
//这里也可以递归,反正是个外置函数,无所谓(递归写法)
/*(struct ListNode* reverseLinkedList(struct ListNode* head){
    if(head==NULL||head->next==NULL){
        return head;
    }
    struct ListNode* Newhead=reverseLinkedList(head->next);
    head->next->next=head;
    head->next=NULL;
    return Newhead;
}
)*/
void reverseLinkedList(struct ListNode* head){
    struct ListNode* pre=NULL;
    struct ListNode* cur=head;
    
    while(cur!=NULL){
        struct ListNode* nextnode=cur->next;
        cur->next=pre;
        pre=cur;
        cur=nextnode;
    }
}

struct ListNode* reverseBetween(struct ListNode* head, int left, int right){
    if(left==right){
        return head;
    }
//增加哑结点,避免不必要的复杂分类讨论
    struct ListNode* dummy=malloc(sizeof(struct ListNode));
    dummy->val=-1;
    dummy->next=head;
    struct ListNode* pre=dummy;

//要习惯用for循环,特别是涉及遍历次数可以精确判断的时候,for循环有时能不用像while循环一样在链表里去模拟遍历
//遍历停到left的前一个结点
    for(int i=0;i<left-1;i++){
        pre=pre->next;
    }

//对于变量多的时候,我们要有习惯的去有意的设置变量名,增强代码的可读性
//停到right上
    struct ListNode* rightnode=pre;
    for(int i=0;i<right-left+1;i++){
        rightnode=rightnode->next;
    }

//记录结点,方便挂链
    struct ListNode* leftnode=pre->next;
    struct ListNode* curr=rightnode->next;

//断链
    pre->next=NULL;
    rightnode->next=NULL;

//反转中间链表
    reverseLinkedList(leftnode);

//接链
    pre->next=rightnode;
    leftnode->next=curr;
    return dummy->next;
}

 

 思路2.头插法

由于上一种思路里面我们遍历一次链表后,在反转部分还要再遍历一遍,导致了不必要的遍历,我们是否可以想一个办法只遍历一遍。

这里用到的办法就是头插法。

记录三个位置,一个是left-1的位置,一个是left位置,一个是left->next位置

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* reverseBetween(struct ListNode* head, int left, int right){
    struct ListNode* dummy=malloc(sizeof(struct ListNode));
    dummy->val=-1;
    dummy->next=head;
    struct ListNode* pre=dummy;

    for(int i=0;i<left-1;i++){
        pre=pre->next;
    }
    struct ListNode* cur=pre->next;
    struct ListNode* next;
    for(int i=0; i<right-left; i++){
        next=cur->next;
        cur->next=next->next;
        next->next=pre->next;
        pre->next=next;
    }
    return dummy->next;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值