来自北大算法课的Leetcode题解:148. 排序链表

代码仓库Github | Leetcode solutions @doubleZ0108 from Peking University.

  • 解法1(超时): 链表插入排序,用move.next进行遍历,把它插入到前面排序好链中合适的位置

    • 改进1:如果当前要移动的元素比有序链尾大则不需要排序

    • 改进2: 不是一个一个插,每次插都一直往后把一串相等的都拿出来,一起插入到之前

    • 改进3(T5% S83%): 打表,记录插过的数字的位置,之后遇见插过的,直接一步到位(要注意要存储freshPos.next,否则freshPos也可能后面插了相同的位置就变了)

      1.jpeg

  • 解法2(T79% S61%): 链表归并排序(自顶向下),首先通过快慢指针找到链表中心,左右分别递归归并,最后合并有序链表

  • 解法3(T32% S24% 按理应该是 T O ( n l o g n )   S O ( 1 ) T_{O(n log n)} \ S_{O(1)} TO(nlogn) SO(1)): 链表归并排序(自底向上),首先一次遍历计算链表总长度L,分别做1+1元素归, 2+2元素归并, …, L/2+L/2元素归并,因为是链表的归并,因此每次都要记住pre和tail指针,同时在两个链表的merge时也要获取到merge后的start和end(整体思想不复杂,但实现时指针为空的判断属实是被恶心到了)

    2.jpeg

  • 解法4: 一些耍赖的方法,一次把链表读成一个数组,排序完再新建一个链表

class ListNode(object):
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

    def __repr__(self) -> str:
        return '{} -> {}'.format(self.val, self.next)

class Solution(object):
       
    def sortList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if not head or not head.next:
            return head

        def merge(left, right):
            move = ListNode(0)
            start = move
            while left and right:
                if left.val < right.val:
                    move.next = left
                    left = left.next
                    move = move.next
                else:
                    move.next = right
                    right = right.next
                    move = move.next
            if left:
                move.next = left
            if right:
                move.next = right
            while move.next:
                move = move.next
            return start.next, move

        self.next = head

        # 获取长度
        L = 0
        move = head
        while move:
            L += 1
            move = move.next

        move = self
        l = 1
        while l < L:
            pre = self
            while pre and pre.next and pre.next.next:
                left = pre.next
                move = left
                for _ in range(l-1):
                    if not move or not move.next:
                        break
                    move = move.next
                    
                right = move.next
                move.next = None
                move = right
                for _ in range(l-1):
                    if not move or not move.next:
                        break
                    move = move.next
                    
                if move:
                    tail = move.next
                    move.next = None
                else:
                    tail = move

                start, end = merge(left, right)
                pre.next = start
                end.next = tail
                pre = end

            l <<= 1
        
        return self.next
        


    def otherSolution(self, head):
        # 解法2
        if not head or not head.next:
            return head

        # 快慢指针找中点
        fast, slow = head, head
        while fast and fast.next and fast.next.next:
            slow = slow.next
            fast = fast.next.next
        right = self.sortList(slow.next)
        slow.next = None
        left = self.sortList(head)

        # 有序链表合并
        ans = self
        while left and right:
            if left.val < right.val:
                ans.next = left
                left = left.next
                ans = ans.next
            else:
                ans.next = right
                right = right.next
                ans = ans.next
        if left:
            ans.next = left
        if right:
            ans.next = right

        return self.next



        # 解法1
        if not head:
            return head

        posTable = {}

        self.next = head
        move = self.next
        while move.next:
            # 改进1 已经比有序链尾大,不需要排序
            if move.next.val >= move.val:
                move = move.next
                continue 

            # 改进2 把一串相等的一起拿出来
            startPos, endPos = move.next, move.next
            while endPos.next and endPos.next.val == startPos.val:
                endPos = endPos.next

            if endPos.val in posTable:
                # 改进3
                freshPos = posTable[endPos.val]
                move.next = endPos.next
                endPos.next = freshPos.next
                freshPos.next = startPos
            else:
                # 从头一个一个看吧
                freshPos = self
                while freshPos.next!=move.next:
                    if freshPos.next.val > endPos.val:
                        move.next = endPos.next
                        endPos.next = freshPos.next
                        freshPos.next = startPos
                        posTable[endPos.val] = freshPos.next
                        break
                    freshPos = freshPos.next

        return self.next


if __name__ == '__main__':
    head = ListNode(4)
    head.next = ListNode(2)
    head.next.next = ListNode(1)
    head.next.next.next = ListNode(3)
    head.next.next.next.next = ListNode(5) 
    head.next.next.next.next.next = ListNode(0) 
    head.next.next.next.next.next.next = ListNode(8)
    head.next.next.next.next.next.next.next = ListNode(-1)
    head.next.next.next.next.next.next.next.next = ListNode(0)
    head.next.next.next.next.next.next.next.next.next = ListNode(9)
    Solution().sortList(head)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要迅速提高算法能力,我建议以下几个方法: 1. 学习基础知识:算法是计算机科学的基石,学习基本的数据结构、算法原理和常见算法的实现是提高算法能力的基础。可以通过阅读经典的教材和参考资料,例如《算法导论》等,加深对算法的理解。 2. 多做题目:练习是提高算法能力的关键。选择一些经典的算法习题,如LeetCode、LintCode等平台上的题目,刷题可以帮助提高对算法的理解和掌握。在解题过程中,要注意思路的清晰和代码的优化,多思考和总结。 3. 参与竞赛:参与编程竞赛,如ACM、TopCoder等,可以锻炼解决问题的能力和对算法的应用。在竞赛中,可以接触到各种各样难度不同的题目,有助于拓宽思路和提高解题的速度。 4. 阅读优秀代码:学习优秀的算法实现是提高算法能力的重要途径。阅读其他人的高质量代码,可以学习别人的解题思路、代码结构和优化技巧,提升自己的编程水平。 5. 参与开源项目:参与开源项目,可以与其他开发者合作,共同解决实际问题,并学习他们的经验和技巧。通过开源社区的交流和贡献,可以不断提高自己的算法和编程能力。 综上所述,要迅速提高算法能力,需要学习基础知识,多做题目,参与竞赛,阅读优秀代码,以及参与开源项目。这些方法可以帮助我们加深对算法的理解,提高解题的效率和质量,从而快速提高算法能力。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

doubleZ0108

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值