第一次参加比赛,结果比想象的好,还以为自己可能一道题都做不出,但看了大佬们的排名,哎。。。。
第一题:方阵中战斗力最弱的 K 行
给你一个大小为 m * n 的方阵 mat,方阵由若干军人和平民组成,分别用 0 和 1 表示。
请你返回方阵中战斗力最弱的 k 行的索引,按从最弱到最强排序。
如果第 i 行的军人数量少于第 j 行,或者两行军人数量相同但 i 小于 j,那么我们认为第 i 行的战斗力比第 j 行弱。
军人 总是 排在一行中的靠前位置,也就是说 1 总是出现在 0 之前。
例子:
输入:mat =
[[1,1,0,0,0],
[1,1,1,1,0],
[1,0,0,0,0],
[1,1,0,0,0],
[1,1,1,1,1]],
k = 3
输出:[2,0,3]
解释:
每行中的军人数目:
行 0 -> 2
行 1 -> 4
行 2 -> 1
行 3 -> 2
行 4 -> 5
从最弱到最强对这些行排序后得到 [2,0,3,1,4]思路:
1.统计每行1的个数存入字典
2.对字典进行排序
知识点整理:
sorted 不会改变原数组的顺序
根据自定义规则来排序:
根据长度
sorted
(chars,key
=
lambda
x:
len
(x))
Out[
92
]: [
'a'
,
'is'
,
'boy'
,
'bruce'
,
'handsome'
]
根据第几个字段
tuple_list
=
[(
'A'
,
1
,
5
), (
'B'
,
3
,
2
), (
'C'
,
2
,
6
)]
#key=lambda x: x[1]中可以任意选定x中可选的位置进行排序
sorted
(tuple_list, key
=
lambda
x: x[
1
])
根据第几个属性
class
tuple_list:
def
__init__(
self
, one, two, three):
self
.one
=
one
self
.two
=
two
self
.three
=
three
def
__repr__(
self
):
return
repr
((
self
.one,
self
.two,
self
.three))
tuple_list_
=
[tuple_list(
'C'
,
1
,
5
), tuple_list(
'A'
,
3
,
2
), tuple_list(
'C'
,
2
,
6
)]
# 首先根据one的位置来排序,然后根据two的位置来排序
sorted
(tuple_list_, key
=
lambda
x:(x.one, x.two))
Out[
112
]: [(
'A'
,
3
,
2
), (
'C'
,
1
,
5
), (
'C'
,
2
,
6
)]
时间,空间:o(nlogn) o(n)
class Solution:
def kWeakestRows(self, mat: List[List[int]], k: int) -> List[int]:
d={}
for i in range(len(mat)):
d[i] = sum(mat[i])
d = sorted(d.items(), key=lambda x:x[1])
res = []
for one in d:
res.append(one[0])
return res[0:k]
class Solution(object):
def kWeakestRows(self, mat, k):
"""
:type mat: List[List[int]]
:type k: int
:rtype: List[int]
"""
tmp = []
res = []
for i,r in enumerate(mat):
tmp.append([sum(r),i])
tmp.sort()
for one in tmp:
res.append(one[1])
return res[:k]
#看看人家的代码简直就是艺术......
class Solution(object):
def kWeakestRows(self, mat, k):
A = [[sum(r), i] for i,r in enumerate(mat)]
A.sort()
return [i for s,i in A][:k]
第二题:数组大小减半
给你一个整数数组
arr
。你可以从中选出一个整数集合,并删除这些整数在数组中的每次出现。返回 至少 能删除数组中的一半整数的整数集合的最小大小。
输入:arr = [3,3,3,3,5,5,5,2,2,7]
输出:2
解释:选择 {3,7} 使得结果数组为 [5,5,5,2,2]、长度为 5(原数组长度的一半)。
大小为 2 的可行集合有 {3,5},{3,2},{5,2}。
选择 {2,7} 是不可行的,它的结果数组为 [3,3,3,3,5,5,5],新数组长度大于原数组的二分之一。思路:
先遍历一次数组统计每个数字的次数,然后对这个存储排序(根据次数字段),然后依次减去次数直到数组长度小于一半。
class Solution(object):
def minSetSize(self, arr):
"""
:type arr: List[int]
:rtype: int
"""
if not arr:
return 0
d = {}
for one in arr:
if one in d:
d[one] += 1
else:
d[one] = 1
l = sorted(d.items(), key=lambda x:x[1], reverse=True)
tmp = 0
count = 0
for one in l:
tmp +=one[1]
count += 1
if tmp >= len(arr)//2:
return count
第三题:分裂二叉树的最大乘积
给你一棵二叉树,它的根为 root 。请你删除 1 条边,使二叉树分裂成两棵子树,且它们子树和的乘积尽可能大。
由于答案可能会很大,请你将结果对 10^9 + 7 取模后再返回
思路:
定义一个空间存储每个节点下的和,如上图节点2的和是11,然后遍历每个节点即可。
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
def maxProduct(self, root: TreeNode) -> int:
def get_sum(root):
if not root:
return 0
ret=root.val+get_sum(root.left)+get_sum(root.right)
mem[root]=ret
return ret
mem={}
_sum=get_sum(root)
ret=0
for k in mem:
ret=max(ret,(_sum-mem[k])*mem[k])
return ret%(10**9+7)
第四题:跳跃游戏 V
给你一个整数数组 arr 和一个整数 d 。每一步你可以从下标 i 跳到:
i + x ,其中 i + x < arr.length 且 0 < x <= d 。
i - x ,其中 i - x >= 0 且 0 < x <= d 。
除此以外,你从下标 i 跳到下标 j 需要满足:arr[i] > arr[j] 且 arr[i] > arr[k] ,其中下标 k 是所有 i 到 j 之间的数字(更正式的,min(i, j) < k < max(i, j))。你可以选择数组的任意下标开始跳跃。请你返回你 最多 可以访问多少个下标。
请注意,任何时刻你都不能跳到数组的外面。
解法:动态规划
具体来说,当位于一个下标时只能是往左或者往右走,如果下一步能走的话,dp转移是dp[i] = max(dp[i], dp[j] + 1)
至于这里为什么要先排序呢,因为,当前坐标的dp值要依赖于比其更低坐标处的dp值,所以先排序,优先计算值小的坐标
class Solution(object):
def maxJumps(self, A, d):
n = len(A)
dp = [1] * n
B = sorted([a, i] for i, a in enumerate(A))
for a, i in B:
j = i - 1
while j >= 0 and A[j] < A[i] and i - j <= d:
dp[i] = max(dp[i], dp[j] + 1)
j -= 1
j = i + 1
while j < n and A[j] < A[i] and j - i <= d:
dp[i] = max(dp[i], dp[j] + 1)
j += 1
return max(dp)