第十周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;
}
}
总结
递归处理。每次处理最左最右最大。