• 61-RotateList


    旋转列表

    给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。

    示例 1:
    输入: 1->2->3->4->5->NULL, k = 2
    输出: 4->5->1->2->3->NULL
    解释:
    向右旋转 1 步: 5->1->2->3->4->NULL
    向右旋转 2 步: 4->5->1->2->3->NULL
    
    示例 2:
    输入: 0->1->2->NULL, k = 4
    输出: 2->0->1->NULL
    解释:
    向右旋转 1 步: 2->0->1->NULL
    向右旋转 2 步: 1->2->0->NULL
    向右旋转 3 步: 0->1->2->NULL
    向右旋转 4 步: 2->0->1->NULL
    
    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/rotate-list
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    

    思路

    和旋转字符串的思路类似,都是循环移位的思想,像取模,空间换时间,时间换空间,三次翻转法等。链表的操作没有字符串那样方便操作,所以三次翻转这种的就很麻烦了。

    下面是 python 完成的(链表在 C 语言中使用结构体完成,在 python 中用类完成,思路是一样的)。首先是确定链表长度(为了确定链表断开和新链表开始的位置);然后能定位到任意节点,对这个节点进行新建链表或者拆除链表的工作。

    我感觉自己代码的问题就在这里,也就是节点定位,这导致代码的性能一般。

    # Definition for singly-linked list.
    class ListNode:
        def __init__(self, x):
            self.val = x
            self.next = None
    
    def LenListNode(ListNode):
        count = 0
        while ListNode is not None:
            count += 1
            ListNode = ListNode.next
        else:
            return count
    
    def ReachListNode(ListNode, i):
        count = 0
        while ListNode:
            if i == count:
                return ListNode
                break
            else:
                count += 1
                ListNode = ListNode.next
    
    class Solution:
        def rotateRight(self, head: ListNode, k: int) -> ListNode:
            n = LenListNode(head)
            if n == 0:
                return None
            else:
                k = k % n
            if k == 0:
                return head
            new_end = ReachListNode(head, n-k-1)
            ReachListNode(new_end, k).next = head
            head = ReachListNode(new_end, 1)
            new_end.next = None
            return head
    
    

    代码改了较长时间。这个过程中自己一共犯了两个错误:

    • 自己的前两次提交,都是忽略了 n 的判断,导致提交失败。
      以后所有涉及到除法的语句,都要先判断除数是否为 0 才能进行除法,取余等操作。这个在以后的提交中需要注意。
    • 最后对于链表进行整合时,正确顺序是:
      尾节点指向头节点--确定新的头节点--确定尾节点。自己先确定了尾节点,这样就把整个链破坏了,再想确定头节点就不容易了。

    其他思路

    直接思路

    把单向链表变成循环链表;找到断开位置;重新确定头尾节点即可。这也是自己的思路,这种思路最大瓶颈就是定位节点:已知头节点,需要定位 尾节点 和 新的头/尾节点。

    下面是较为完整的代码实现:实际上下面的代码执行时间是64ms,比自己的多出20ms;内存相似。自己和它最大的区别就是使用了函数封装了功能;在遍历次数上都是两遍。我觉得这个差别不大。而且如果真的要从效率而言,C/C++才是最佳选择。

    这段代码的另一个优点是较好的书写习惯和较为完整的考虑了各种情况

    class Solution:
        def rotateRight(self, head: 'ListNode', k: 'int') -> 'ListNode':
            # base cases
            if not head:         # 空链表
                return None
            if not head.next:    # 链表只有一个元素
                return head
            
            # close the linked list into the ring
            old_tail = head
            n = 1
            while old_tail.next:
                old_tail = old_tail.next    # 定位到尾节点
                n += 1                      # 确定链表长度
            old_tail.next = head
            
            # find new tail : (n - k % n - 1)th node
            # and new head : (n - k % n)th node
            new_tail = head
            for i in range(n - k % n - 1):
                new_tail = new_tail.next    # 新链表的尾节点(new_end)
            new_head = new_tail.next        # 新链表的头节点
            
            # break the ring
            new_tail.next = None
            
            return new_head
    
    作者:LeetCode
    链接:https://leetcode-cn.com/problems/rotate-list/solution/xuan-zhuan-lian-biao-by-leetcode/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    

    双指针

    这是针对上面思路的优化,对于效率的提升很明显。做法是:

    • 指针 P1 先从 0 遍历到 K,指针 P2 开始从0遍历
    • 两者之间始终差 K,直到 P1 遍历到尾节点
    • P1 指向旧链表的尾节点;P2指向新链表的尾节点,P2的下一个节点就是新链表的头节点

    用列表模拟链表

    既然链表不好操作,那么先把所有元素存到列表中;然后用一行代码(189-RotateArray中python只用一行代码实现)实现;最后再转换成链表。

    总结

    链表题目做到最后,指针(单指针/双指针) + 列表(模拟队列/栈) 的策略用得较多。双指针的策略效率更高。直接去解也可以,只要代码写的好,调试调的快,就没有问题。

  • 相关阅读:
    delphi正则表达式
    delphi将字符串转换成stringlist
    spring中@Conditional注解
    spring中@Profile的作用
    spring中的bean的生命周期
    java新特性stream
    lambda表达式
    springBoot--组合注解RestController,GetMapping,PostMapping
    idea配置svn,jdk,maven
    一次记录 java非web项目部署到linux
  • 原文地址:https://www.cnblogs.com/rongyupan/p/12633050.html
Copyright © 2020-2023  润新知