链表之翻转从位置m到n的链表

leetcode 92. 反转链表 II

反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。

说明:
1 ≤ m ≤ n ≤ 链表长度。

示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL

翻转链表:

(迭代版本)

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        pre = None
        curr = head
        while curr:
            nex = curr.next
            curr.next = pre
            pre = curr
            curr = nex
        return pre

(递归版本)
在这里插入图片描述
在这里插入图片描述
base case:如果链表只有一个节点的时候反转也是它自己,直接返回即可。
当链表递归反转之后,新的头节点是last,而之前的head变成了最后一个节点,别忘了链表的末尾要指向 None

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        if not head:
        	return None
        if not head.next:
        	return head
        last = self.reverseList(head.next)
        head.next.next = head
        head.next = None
        return last

反转链表前 N 个节点

在这里插入图片描述
在这里插入图片描述

base case 变为n == 1,反转一个元素,就是它本身,同时要记录后驱节点。
刚才我们直接把head.next设置为 None,因为整个链表反转后原来的head变成了整个链表的最后一个节点。但现在head节点在递归反转之后不一定是最后一个节点了,所以要记录后驱successor(第 n + 1 个节点),反转之后将head连接上。

class Solution:
	successor = None
    def reverseN(self, head: ListNode, n: int) -> ListNode:
        if not head:
        	return None
        if n == 1:
        	successor = head.next
        	return head
        last = self.reverseN(head.next, n - 1)
        head.next.next = head
        head.next = successor
        return last

方案一:

先找到要翻转的 a 和 b 点,注意保存 a 的前驱节点 prea 和 b 的后继节点 bnex ,然后翻转从 a 到 b 的部分,之后修改指针指向,让prea.next = b, a.next = bnex
缺点是进行了多次扫描,代码如下:
翻转从m到n的完整代码

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:
        if m == n:
            return head
        dummpy = ListNode(None)
        dummpy.next = head
        prea, b = dummpy, dummpy
        for _ in range(m - 1):
            prea = prea.next
        for _ in range(n):
            b = b.next
        
        a = prea.next
        bnex = b.next
        pre = prea
        curr = prea.next
        
        while curr != bnex:
            nex = curr.next
            curr.next = pre
            pre = curr
            curr = nex
        
        prea.next = b 
        a.next = bnex
        return dummpy.next

方案二:

一次遍历,在遍历的时候同时进行翻转
看代码

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:
        if m == n:
            return head
        dummpy = ListNode(None)
        dummpy.next = head
        
        pre = dummpy
        for i in range(m - 1):
            pre = pre.next
        # pre 代表第m节点的前一个节点
        
        curr = pre.next # curr代表第m个节点

        temp_pre = ListNode(None) # 临时节点便于翻转链表

        for i in range(m, n + 1): # 翻转从m到n的节点,注意是n+1,翻转完,temp_pre指向第n个节点,curr指向第n+1个节点
            nex = curr.next
            curr.next = temp_pre
            temp_pre = curr
            curr = nex
        
        pre.next.next = curr # 第m个节点的下一个指向第n+1个节点
        pre.next = temp_pre # 第m-1个节点的下一个指向第n个节点

        return dummpy.next


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值