反转链表

反转链表

剑指 Offer 24. 反转链表

92. 反转链表 II


一.反转整个单链表

剑指 Offer 24. 反转链表

链表的结构:1->2->3->4->5->NULL

class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None
1.迭代方法
  • 分析:

    假设链表的结构是:1–>2–>3–>N

    反转后的结果就是N<–1<–2<–3

    也就是将所有的箭头换向,然后在最前面加个None,最后的None去掉

      假设每个节点有三个方向,pre,cur,nxt分别对应前面被指向的节点,当前节点,指向的节点(如:节点2的pre就是1节点,cur就是当前的2节点,nxt就是3节点),由于1节点没有pre,假设为None
    

​ 那么进行迭代的过程就是:

  1. 将1节点指向的2节点打断,指向pre节点(假设的N节点),然后将pre,cur,nxt向后移动一格,再进行下一次迭代,此时的结果就是:N<--1 2-->3-->N, pre为1节点,cur为2节点,nxt为3节点
  2. 将cur(2节点)指向nxt(3节点)的箭头打断,重新指向pre(1节点),然后将pre,cur,nxt向后移动一格,再进行下一次迭代,此时的结果就是:N<--1<--2 3-->N, pre为2节点,cur为3节点,nxt为None
  3. 将cur(3节点)指向nxt(None)的箭头打断,重新指向pre(2节点),然后将pre,cur,nxt向后移动一格,再进行下一次迭代,此时的结果就是:N<--1<--2<--3 N, pre为3节点,cur为None,nxt没有,当cur为None时,停止迭代
  4. 由上可以看到,最后反转后的链表头部head就是3节点对应的pre,返回pre
  • 代码

    • 伪代码
    class Solution:
        def reverseList(self, head: ListNode) -> ListNode:
            pre = None
            cur = head
            nxt = cur.next
            while cur != None:
                cur.next = pre
                pre = cur
                cur = nxt
                nxt = cur.next
            return pre
    

    考虑到cur可能没有next,优化代码后

    • 代码
    class Solution:
        def reverseList(self, head: ListNode) -> ListNode:
            pre = None
            cur = head
            while cur:
                nxt = cur.next
                cur.next = pre
                pre = cur
                cur = nxt
            return pre
    
2.递归方法
二.反转链表前 N 个节点

将链表的前 n 个节点反转(n <= 链表长度)

输入: 1–>2–>3–>4–>N , 3

输出: 3–>2–>1–>4–>N

1.迭代方法
  • 分析

    按照反转整个链表的方式,区别就在于第1步和最后判断迭代结束的第三步存在区别:

    • 在第1步中,将1节点指向2节点的指向打断,指向None应该变为指向第n+1节点
    • 其他的不变,还是反转
    • 到第3步中,当cur为None时,停止迭代变为当cur为第n+1节点时,停止迭代
  • 代码

    class Solution:
        def reverseList(self, head: ListNode,n) -> ListNode:
            # 记录第n+1节点为n_and_1
            tmp = head
            for i in range(0,n):
                tmp = tmp.next
            n_and_1 = tmp
            # 迭代反转
            pre = None
            cur = head
            while cur.val != n_and_1.val:
                nxt = cur.next
                if pre:
                    # pre不为None时,调换箭头方向
                    cur.next = pre
                else:
                    # pre为None时,说明是第一个节点,则需要指向n+1节点
                    cur.next = n_and_1
                pre = cur
                cur = nxt
            return pre
    
2.递归方法
三、反转链表的一部分

给一个索引区间 [m,n](索引从 1 开始),仅仅反转区间中的链表元素。

输入: 1–>2–>3–>4–>5–>N , 2, 4

输出: 1–>4–>3–>2–>5–>N

92. 反转链表 II

1.迭代方法
  • 分析:

    定义head为第m个节点,last为第n个节点

    按照反转整个链表的方式分析,存在以下区别:

    • 第m-1个节点指向第m个节点的箭头,应该改为第m-1个节点指向第n个节点.(如果m==1,则没有m-1,不需要操作,设置pre为None)
    • 如果cur是开始的head(第m个节点),则不是将指向nxt的箭头指向pre,而是指向第n+1节点
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:
        # 记录起始的pre(第m-1个节点)
        # 记录起始的cur
        if m == 1:
            pre = None
            cur = head
        else:
            tmp = head
            for i in range(0, m - 2):
                tmp = tmp.next
            pre = tmp
            cur = pre.next
        # 记录第n节点为 n_node
        # 记录第n+1节点为 n_and_1
        tmp = head
        for i in range(0, n - 1):
            tmp = tmp.next
        n_node = tmp
        n_and_1 = n_node.next

        # 迭代反转
        for i in range(0, n - m + 1):
            nxt = cur.next
            if i == 0:
                if m != 1:
                    pre.next = n_node
                cur.next = n_and_1
            else:
                cur.next = pre
            pre = cur
            cur = nxt
        return head if m != 1 else pre


if __name__ == '__main__':
    head = ListNode(1)
    head.next = ListNode(2)
    head.next.next = ListNode(3)
    head.next.next.next = ListNode(4)
    head.next.next.next.next = ListNode(5)

    so = Solution()
    head = so.reverseList(head, 2, 4)

    while head != None:
        print(head.val)
        head = head.next
  1. 迭代最优方法:

    • 分析
    1. 在链表最前面加上一个p节点:p–>1–>2–>3–>4–>5–>N
    p_node = ListNode(0)
    p_node.next = head
    
    1. 定义pre,cur指针,分别指向p节点和head节点(1节点)
    pre, cur = p_node, head
    
    1. 移动pre,cur节点,使cur节点到达left节点,并且将此时的pre节点和cur节点记录下来,将指定的区域倒换后,这两个节点要分别指向right节点和right+1节点
    for _ in range(1, left):
        pre = pre.next
        cur = cur.next
    first, second = pre, cur
    

    此时:

    p–>1–>2–>3–>4–>5–>N

    pre–>1节点 ,cur–>2节点

    1. 将2-4节点中间区域的箭头掉头
    for _ in range(left, right + 1):
        nxt = cur.next
        cur.next = pre
        pre = cur
        cur = nxt
    

    此时:

    p–>1<——>2<–3<–4 5–>N

    pre指向4节点,cur指向5节点

    1. 将记录下来的节点分别指向right节点和right+1节点
    first.next = pre
    second.next = cur
    

    此时:p–>1–>4–>3–>2–>5–>N

  • 最终代码
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next


class Solution:
    def reverseList(self, head: ListNode, left, right) -> ListNode:
        p_node = ListNode(0)
        p_node.next = head
        pre, cur = p_node, head
        for _ in range(1, left):
            pre = pre.next
            cur = cur.next
        first, second = pre, cur
        for _ in range(left, right + 1):
            nxt = cur.next
            cur.next = pre
            pre = cur
            cur = nxt
        first.next = pre
        second.next = cur
        return p_node.next

if __name__ == '__main__':
    head = ListNode(1)
    head.next = ListNode(2)
    head.next.next = ListNode(3)
    head.next.next.next = ListNode(4)
    head.next.next.next.next = ListNode(5)

    so = Solution()
    head = so.reverseList(head, 1, 4)

    while head != None:
        print(head.val)
        head = head.next
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值