python算法日记(链表系列)_leetcode 92. 反转链表 II

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

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

示例:

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-linked-list-ii

方法一:头插法

# 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 not head or not head.next or m==n: #不先处理这些情况会慢一些
            return head
        dummy = ListNode(0)
        dummy.next = head  # 头插法
        pre = dummy  #dummy留着不动,用来最后返回
        for _ in range(m-1):
            pre = pre.next   #到要处理的节点的前一个
        tail = pre.next  #第m个节点,处理完后是末尾的n位置节点
        cur = pre.next.next
        for _ in range(n-m):  #反转
            tmp = pre.next   
            tmp1 = cur.next
            pre.next = cur  #pre的位置是不动的,一直往pre后面插当前cur节点
            cur.next = tmp
            cur = tmp1
        tail.next = cur #反转完后cur指向最后不用反转的部分,把它连上去
        return dummy.next

比照示例,这种方法就是往m-1位置后面一直插节点。因为pre部分一直连着要反转的部分,所以只要最后连接tail部分就好

整个dummy的变化:

0->1->3<->2 4->5->NULL

0->1->4->3<->2 5->NULL   # 这里如果不把2.next指针指向5会死循环超出时间限制

0->1->4->3->2->5->NULL

这里把dummy放到最开头是为了避免m=1的情况处理不到

方法二:指针反转

class Solution:
    def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:
        if not head or not head.next or m==n:
            return head
        dummy = ListNode(0)
        dummy.next = head
        prehead = dummy  #不用反转的前面部分
        for i in range(m-1):
            prehead = prehead.next
        cur = prehead.next #开始反转的位置
        tail = prehead.next
        pre = None #一个空的前向指针
        for i in range(n-m+1): #这里n-m+1,才能pre指向n,cur指向n+1
            tmp = cur.next
            cur.next = pre
            pre = cur
            cur = tmp
        prehead.next = pre  #前连中
        tail.next = cur   # 连上尾
        return dummy.next

参照实例,反转后dummy:0->1->2, pre:2<-3<-4 , cur:5->NULL

连起来:1,2之间断掉 0->1->4->3->2 ,再用2接上5,dummy:0->1->4->3->2->5->NULL

这里不在最前面插dummy也处理不了m=1的情况

写成这样更快一点,方法差不多

# 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
        dummy = ListNode(0)
        dummy.next = head
        a, d = dummy, dummy
        for _ in range(m - 1):
            a = a.next
        for _ in range(n):
            d = d.next
        b, c = a.next, d.next
        pre = b
        cur = pre.next
        while cur != c:
            next = cur.next
            cur.next = pre
            pre = cur
            cur = next
        a.next = d
        b.next = c
        return dummy.next

 笨办法也可以过:用list存处理好了再接上去

# 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 not head or not head.next or m==n:
            return head
        res = []
        while(head):
            res.append(head.val)
            head = head.next
        lista = res[:m-1]
        listb = res[m-1:n][::-1]
        listc = res[n:]
        lista.extend(listb)
        lista.extend(listc)
        cur = ListNode(0)
        dummy = cur
        for i in lista:
            cur.next = ListNode(i)
            cur = cur.next
        return dummy.next

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值