第十周LeetCode记录

11.18 46. 拼接最大数

给定长度分别为 m 和 n 的两个数组,其元素由 0-9 构成,表示两个自然数各位上的数字。现在从这两个数组中选出 k (k <= m + n) 个数字拼接成一个新的数,要求从同一个数组中取出的数字保持其在原数组中的相对顺序。

求满足该条件的最大数。结果返回一个表示该最大数的长度为 k 的数组。

输入:
nums1 = [3, 4, 6, 5]
nums2 = [9, 1, 2, 5, 8, 3]
k = 5
输出:
[9, 8, 6, 5, 3]

输入:
nums1 = [6, 7]
nums2 = [6, 0, 4]
k = 5
输出:
[6, 7, 6, 0, 4]

最优解

class Solution:
    def maxNumber(self, nums1, nums2, k):

        def pick_max(nums, k):
            stack = []
            drop = len(nums) - k
            for num in nums:
                while drop and stack and stack[-1] < num:
                    stack.pop()
                    drop -= 1
                stack.append(num)
            return stack[:k]

        def merge(A, B):
            ans = []
            while A or B:
                bigger = A if A > B else B
                ans.append(bigger[0])
                bigger.pop(0)
            return ans

        return max(merge(pick_max(nums1, i), pick_max(nums2, k-i)) for i in range(k+1) if i <= len(nums1) and k-i <= len(nums2))

总结

从2个数组共取k个数字,遍历各种情况。分治解决

pick_max是从nums数组里取前k位组成新的数组,merge是将两数组合并为最大数组

思考一下时间复杂度和空间复杂度是多少

11.19 47. 不同字符的最小子序列

返回字符串 text 中按字典序排列最小的子序列,该子序列包含 text 中所有不同字符一次。

输入:"cdadabcc"
输出:"adbc"

输入:"abcd"
输出:"abcd"

输入:"ecbacba"
输出:"eacb"

输入:"leetcode"
输出:"letcod"

思路

跟上面的题型一样,利用栈来解

我的解

class Solution:
    def smallestSubsequence(self, s: str) -> str:
        from collections import Counter
        s_dic = Counter(s)
        stack = []
        for i in s:
            if i not in stack:
                while stack and stack[-1] >= i and s_dic[stack[-1]] > 0:
                    stack.pop()
                stack.append(i)
            s_dic[i] -= 1

        return ''.join(stack)

11.20 48. 对称的二叉树

请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。

例如,二叉树 [1,2,2,3,4,4,3] 是对称的。

    1
   / \
  2   2
 / \ / \
3  4 4  3

但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:

    1
   / \
  2   2
   \   \
   3    3

最优解

class Solution:
    @classmethod
    def isSymmetric(self, root: TreeNode) -> bool:
        
        def recrue(Left,Right):
            if not Left and not Right:
                return True
            
            if not Left or not Right or Left.val != Right.val:
                return False

            return recrue(Left.left,Right.right) and recrue(Left.right,Right.left)

        return recrue(root.left,root.right) if root else True

总结

和29题 另一个树的子树同样的方法,递归遍历对称树的定义即可。

11.21 49.最接近原点的k个点

我们有一个由平面上的点组成的列表 points。需要从中找出 K 个距离原点 (0, 0) 最近的点。

(这里,平面上两点之间的距离是欧几里德距离。)

你可以按任何顺序返回答案。除了点坐标的顺序之外,答案确保是唯一的。

输入:points = [[1,3],[-2,2]], K = 1
输出:[[-2,2]]
解释: 
(1, 3) 和原点之间的距离为 sqrt(10),
(-2, 2) 和原点之间的距离为 sqrt(8),
由于 sqrt(8) < sqrt(10),(-2, 2) 离原点更近。
我们只需要距离原点最近的 K = 1 个点,所以答案就是 [[-2,2]]。

输入:points = [[3,3],[5,-1],[-2,4]], K = 2
输出:[[3,3],[-2,4]]
(答案 [[-2,4],[3,3]] 也会被接受。)

思路

遍历每个点,排序取前k。

我的解

class Solution:
    def kClosest(self, points: List[List[int]], K: int) -> List[List[int]]:
        import math
        def calc_dis(point):
            x, y = point
            return math.sqrt(x ** 2 + y ** 2)

        return sorted(points,key=lambda k:calc_dis(k))[:K]

最优解

优先队列

我们可以使用一个优先队列(大根堆)实时维护前 KK 个最小的距离平方。

首先我们将前 KK 个点的编号(为了方便最后直接得到答案)以及对应的距离平方放入优先队列中,随后从第 K+1K+1 个点开始遍历:如果当前点的距离平方比堆顶的点的距离平方要小,就把堆顶的点弹出,再插入当前的点。当遍历完成后,所有在优先队列中的点就是前 KK 个距离最小的点。

class Solution:
    def kClosest(self, points: List[List[int]], K: int) -> List[List[int]]:
        q = [(-x ** 2 - y ** 2, i) for i, (x, y) in enumerate(points[:K])]
        heapq.heapify(q)
        
        n = len(points)
        for i in range(K, n):
            x, y = points[i]
            dist = -x ** 2 - y ** 2
            heapq.heappushpop(q, (dist, i))
        
        ans = [points[identity] for (_, identity) in q]
        return ans

总结

取前几个后几个的题型,优先想到用堆处理。

11.23 50. 最大二叉树

给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下:

二叉树的根是数组中的最大元素。
左子树是通过数组中最大值左边部分构造出的最大二叉树。
右子树是通过数组中最大值右边部分构造出的最大二叉树。
通过给定的数组构建最大二叉树,并且输出这个树的根节点。

输入:[3,2,1,6,0,5]
输出:返回下面这棵树的根节点:

      6
    /   \
   3     5
    \    / 
     2  0   
       \
        1

最优解

public class Solution {
    public TreeNode constructMaximumBinaryTree(int[] nums) {
        return construct(nums, 0, nums.length);
    }
    public TreeNode construct(int[] nums, int l, int r) {
        if (l == r)
            return null;
        int max_i = max(nums, l, r);
        TreeNode root = new TreeNode(nums[max_i]);
        root.left = construct(nums, l, max_i);
        root.right = construct(nums, max_i + 1, r);
        return root;
    }
    public int max(int[] nums, int l, int r) {
        int max_i = l;
        for (int i = l; i < r; i++) {
            if (nums[max_i] < nums[i])
                max_i = i;
        }
        return max_i;
    }
}

总结

递归处理。每次处理最左最右最大。

posted @ 2020-11-28 12:40  Jimmyhe  阅读(102)  评论(0编辑  收藏  举报