• 第11周leetcode记录


    11.24 51. 鸡蛋掉落

    你将获得 K 个鸡蛋,并可以使用一栋从 1 到 N 共有 N 层楼的建筑。

    每个蛋的功能都是一样的,如果一个蛋碎了,你就不能再把它掉下去。

    你知道存在楼层 F ,满足 0 <= F <= N 任何从高于 F 的楼层落下的鸡蛋都会碎,从 F 楼层或比它低的楼层落下的鸡蛋都不会破。

    每次移动,你可以取一个鸡蛋(如果你有完整的鸡蛋)并把它从任一楼层 X 扔下(满足 1 <= X <= N)。

    你的目标是确切地知道 F 的值是多少。

    无论 F 的初始值如何,你确定 F 的值的最小移动次数是多少?

    输入:K = 1, N = 2
    输出:2
    解释:
    鸡蛋从 1 楼掉落。如果它碎了,我们肯定知道 F = 0 。
    否则,鸡蛋从 2 楼掉落。如果它碎了,我们肯定知道 F = 1 。
    如果它没碎,那么我们肯定知道 F = 2 。
    因此,在最坏的情况下我们需要移动 2 次以确定 F 是多少。
    
    

    总结

    看了一下题意的视频,难。理解了此题的动态规划思路:如果碎了,次数相当于用剩余的鸡蛋往下降一层。如果没碎,次数相当于用所有的鸡蛋往上一层。可以一直递推到1个鸡蛋或是1层楼的情况。

    dp(K,N)=1+ min (max(dp(K−1,X−1),dp(K,N−X)))
    

    待探究

    11.25 52. 顺时针打印矩阵

    输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。

    [
     [ 1, 2, 3 ],
     [ 4, 5, 6 ],
     [ 7, 8, 9 ]
    ]
    输出: [1,2,3,6,9,8,7,4,5]
    
    [
      [1, 2, 3, 4],
      [5, 6, 7, 8],
      [9,10,11,12]
    ]
    输出:[1,2,3,4,8,12,11,10,9,5,6,7]
    

    思路

    右边停止了向下,向下停止了向左,向左停止了向上,向上停止了回到向右。

    最优解

    class Solution:
        def spiralOrder(self, matrix: list) -> list:
            if not matrix or not matrix[0]:
                return list()
    
            rows, columns = len(matrix), len(matrix[0])
            visited = [[False] * columns for _ in range(rows)]
            total = rows * columns
            order = [0] * total
    
            dir = [(0, 1), (1, 0), (0, -1), (-1, 0)]
            row, column = 0, 0
            dir_index = 0
            for i in range(total):
                order[i] = matrix[row][column]
                visited[row][column] = True
                nextRow, nextColumn = row + dir[dir_index][0], column + dir[dir_index][1]
                if not (0 <= nextRow < rows and 0 <= nextColumn < columns and not visited[nextRow][nextColumn]):
                    dir_index = (dir_index + 1) % 4
                row += dir[dir_index][0]
                column += dir[dir_index][1]
    
            return order
    
    

    总结

    dir_index = (dir_index + 1) % 4是方向循环的关键。

    11.27 53. 相似度为k的字符串

    如果可以通过将 A 中的两个小写字母精确地交换位置 K 次得到与 B 相等的字符串,我们称字符串 A 和 B 的相似度为 K(K 为非负整数)。

    给定两个字母异位词 A 和 B ,返回 A 和 B 的相似度 K 的最小值。

    输入:A = "ab", B = "ba"
    输出:1
    
    输入:A = "abac", B = "baca"
    输出:2
    
    输入:A = "aabc", B = "abca"
    输出:2
    

    待探究

    最优解和图、环有关。

    11.28 54. 不同的二叉搜索树

    给定一个整数 n,生成所有由 1 ... n 为节点所组成的 二叉搜索树

    输入:3
    输出:
    [
      [1,null,3,2],
      [3,2,null,1],
      [3,1,null,null,2],
      [2,1,3],
      [1,null,2,null,3]
    ]
    解释:
    以上的输出对应以下 5 种不同结构的二叉搜索树:
    
       1         3     3      2      1
               /     /      /       
         3     2     1      1   3      2
        /     /                        
       2     1         2                 3
    

    思路

    暴力破解时间复杂度n方。

    最优解

    递归
    class Solution:
        @classmethod
        def generateTrees(self, n: int) -> list:        
            def get_ans(start, end):
                import itertools
                ans = []
                # 此时无数字,将null加入结果中
                if start > end:
                    return [None]
                # 只有一个数字,当前数字作为一棵树加入结果中
                if start == end:
                    return [TreeNode(start)]
                # 每个数字作为根节点
                for i in range(start, end+1):
                    # 得到所有可能的左子树
                    left_trees = get_ans(start, i-1)
                    # 得到所有可能的右子树
                    right_trees = get_ans(i+1, end)
                    # 组合左子树和右子树
                    for left_tree, right_tree in itertools.product(left_trees, right_trees):
                        root = TreeNode(i)
                        root.left = left_tree
                        root.right = right_tree
                        ans.append(root)
                return ans
    
            if n == 0:
                return [None]
            return get_ans(1,n)
    
    
    动态规划(待研究)

    解法3是动态规划,没有读懂此解法的状态转移的原理,待研究。

    11.30 55. 摆动排序

    给定一个无序的数组 nums,将它重新排列成 nums[0] < nums[1] > nums[2] < nums[3]... 的顺序。

    输入: nums = [1, 5, 1, 1, 6, 4]
    输出: 一个可能的答案是 [1, 4, 1, 5, 1, 6]
    
    输入: nums = [1, 3, 2, 2, 3, 1]
    输出: 一个可能的答案是 [2, 3, 1, 3, 1, 2]
    

    思路

    将数组heapfy,后序遍历。(错误,变成堆后不一定变成二叉搜索树,将数组变成二叉搜索树后,利用后序遍历)

    后序遍历可以实现,一定要是个平衡二叉搜索树。

    • 堆并不是平衡二叉搜索树
    • 堆的父节点要么都大于子节点,要么都小于子节点。

    最优解

    class Solution:
        def wiggleSort(self, nums: List[int]) -> None:
            """
            Do not return anything, modify nums in-place instead.
            """
            n = len(nums)
            if n < 2:return nums
            mid = (0 + n-1) // 2 # 中位数索引
            
    
            # 快速排序中的一次划分
            def partition(begin,end):
                left,right = begin,end
                while left < right:
                    while left < right and nums[left] < nums[right]:right -= 1
                    if left < right:
                        nums[left],nums[right] = nums[right],nums[left]
                        left += 1
                    while left < right and nums[left] < nums[right]: left += 1
                    if left < right:
                        nums[left],nums[right] = nums[right],nums[left]
                        right -= 1
                return left
    
            # 找到中位数对应的数值
            left,right = 0, n-1
            while True:
                pivot = partition(left,right)
                if pivot == mid:break
                elif pivot > mid:right = pivot - 1
                else:left = pivot + 1
    
            # 三路划分(荷兰旗)
            midNum = nums[mid]
            left,curr,right = 0, 0, n-1
            while curr < right:
                if nums[curr] < midNum:
                    nums[left],nums[curr] = nums[curr],nums[left]
                    left += 1
                    curr += 1
                elif nums[curr] > midNum:
                    nums[curr],nums[right] = nums[right],nums[curr]
                    right -= 1
                else:
                    curr += 1
    
            # 交叉合并
            small,big ,_nums = mid,n-1,nums[:]
            for i in range(n):
                if i%2 == 0:
                    nums[i] = _nums[small]
                    small -= 1
                else:#big
                    nums[i] = _nums[big]
                    big -= 1
    
    

    总结

    例如,对于数组[1,1,2,2,3,3],分割为[1,1,2]和[2,3,3],虽然A和B都出现了2,但穿插后为[1,2,1,3,2,3],满足要求。
    而如果2的个数再多一些,即[1,1,2,2,2,3],分割为[1,1,2]和[2,2,3],最终结果为[1,2,1,2,2,3],来自A的2和来自B的2出现在了相邻位置。

    出现这一问题是因为重复数在A和B中的位置决定的,因为r在A尾部,B头部,所以如果r个数太多(大于等于(length(nums) + 1)/2),就可能在穿插后相邻。要解决这一问题,我们需要使A的r和B的r在穿插后尽可能分开。一种可行的办法是将A和B反序:

    例如,对于数组[1,1,2,2,2,3],分割为[1,1,2]和[2,2,3],分别反序后得到[2, 1, 1]和[3, 2, 2],此时2在A头部,B尾部,穿插后就不会发生相邻了。

    因此,我们第一步其实不需要进行排序,而只需要找到中位数即可

    找到中位数后,我们需要利用3-way-partition算法将中位数放在数组中部,同时将小于中位数的数放在左侧,大于中位数的数放在右侧。保证其左侧元素不大于自身,右侧元素不小于自身。我们只需要将数组从中间等分为2个部分,然后反序,穿插,即可得到最终结果。

  • 相关阅读:
    WebStorm2019
    微信公众号互阅平台-真实提高阅读量-「作者加鸡腿」
    macos 致命错误: 在类路径或引导类路径中找不到程序包 java.lang
    IDEA2020激活码 / IDEA 2020.1.2激活破解教程
    Linux命令大全
    2019年终总结-2020展望「定版」
    SpringBoot如何切换Redis默认库
    uniapp增加百度统计代码(h5)
    修改MyEclipse/Eclipse左侧文字大小(MacOS/Windows)
    Invalid connection string format, a valid format is: "host:port:sid"
  • 原文地址:https://www.cnblogs.com/jimmyhe/p/14094958.html
Copyright © 2020-2023  润新知