编程导航算法通关村第二关 | 指定区间反转问题

上回说到链表反转是学历链表的重中之重,而链表反转的拓展问题更是高频问题,本文来集中研究一下指定区间反转问题

指定区间反转

LeetCode92:给你单链表的头指针 head 和两个整数 leftright ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。
在这里插入图片描述

解法1. 头插法

反转核心思路如下:
每次都先让p指向q的后继,然后让q指向p(也就是pre的后继),最后让pre指向q
在这里插入图片描述
来看下代码:

ListNode* reverseBetween(ListNode* head, int left, int right) {
    ListNode* res = (ListNode*)malloc(sizeof(ListNode));
    res->next = head;
    ListNode* pre = res;
    // 初始让pre指向反转区间的前一个节点
    for(int i = 0; i < left - 1; i++) {
        pre = pre->next;
    }
    // 定义工作指针
    ListNode* p = pre->next;
    ListNode* q = p->next;
    // 只对区间节点操作
    for(int i = 0; i < right - left; i++) {
        // 核心操作
        p->next = q->next;
        q->next = pre->next;
        pre->next = q;
        // 更新工作指针
        q = p->next;
    }
    return res->next;
}

解法2. 穿针引线法

先举一个例子,比如我们需要把蓝色区间翻转
在这里插入图片描述
我们可以把这个链表分成三部分,把中间部分翻转,然后在拼接回去,如下图:
在这里插入图片描述

  1. 先把待翻转区域翻转
  2. 把 pre 的 next 指针指向反转以后的链表头节点,把反转以后的链表的尾节点的 next 指针指向 succ。
    细节方面我们直接看代码:
ListNode* reverseBetween(ListNode* head, int left, int right) {
    ListNode* ans = (ListNode*)malloc(sizeof(ListNode));
    ans->next = head;
    ListNode* pre = ans;
// 初始化四个指针
    // 1. 让pre指向待翻转区间的左边第一个元素
    for(int i = 0; i < left - 1; i++) 
        pre = pre->next;
    // 2. 让rightNode指向待翻转区间的右边界元素
    ListNode* rightNode = pre;
    for(int i = 0; i < right - left + 1; i++) 
        rightNode = rightNode->next;
    // 3. 让left指向待翻转区间的左边界元素
    ListNode* leftNode = pre->next;
    // 4. 让succ指向待翻转区间的右边第一个元素
    ListNode* succ = rightNode->next;
// 断开链接分成三部分
    pre->next = NULL;
    rightNode->next = NULL;
// 区间反转
    reverse(leftNode);
// 拼接三部分
    leftNode->next = succ;
    pre->next = rightNode;
    return ans->next;
}
ListNode* reverse(ListNode* head) {
    ListNode* pre = NULL;
    ListNode* p = head;
    while(p != NULL) {
        ListNode* q = p->next;
        p->next = pre;
        pre = p;
        p = q;
    }
    return pre;
}

这里需要注意的点是要先断开链接再反转,顺序不能反了。reverse方法用到的就是上一篇编程导航算法通关村第二关 | 终于学会链表翻转啦写到的直接操作链表实现翻转,这个算法很重要,一定要掌握

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值