题目描述
给你一个大小为 m * n 的矩阵 mat,矩阵由若干军人和平民组成,分别用 1 和 0 表示。
请你返回矩阵中战斗力最弱的 k 行的索引,按从最弱到最强排序。
如果第 i 行的军人数量少于第 j 行,或者两行军人数量相同但 i 小于 j,那么我们认为第 i 行的战斗力比第 j 行弱。
军人 总是 排在一行中的靠前位置,也就是说 1 总是出现在 0 之前。
我自己的暴力解法:
class Solution:
def kWeakestRows(self, mat, k: int):
hashmap = {}
a_list = []
for i in range(len(mat)):
sum_ = sum(mat[i])
hashmap[i] = sum_ # {0:10,1:12,2:13}
d_order = sorted(hashmap.items(),key=lambda x:x[1],reverse=False)
print(d_order)
for i in range(k):
a_list.append(d_order[i][0])
return a_list
我先对每行士兵的战力进行计算,计算后将每行士兵的行号和战力值保存在字典中,然后对字典根据战力由弱到强的顺序排序,然后遍历列表把士兵行号取出来,存到列表中,截取前面k个就是最弱的第K行。
class Solution:
def kWeakestRows(self, mat, k: int):
a = [sum(row) for row in mat] #[2, 4, 1, 2, 5]计算出了每行的战力
print(a)
ma = max(a)
mi = min(a)
ans = []
while True:
for index, val in enumerate(a):
if val == mi:
ans.append(index)
a[index] = ma + 1
if len(ans)==k:
return ans
mi = min(a)
这个方法是先把每行的战力计算出来保存在一个列表里面,这个列表的顺序就是之前的行号。然后枚举列表,找到最小值,更新最小值。
依次按照战力由弱到强将行号保存到列表中。这个方法还有我自己理解还有优化空间。
class Solution:
def kWeakestRows(self, mat: List[List[int]], k: int) -> List[int]:
a = [sum(row) for row in mat]
mi = min(a)
ma = max(a)
ans = []
while True:
ans.append(a.index(mi))
a[a.index(mi)] = ma + 1
if len(ans) == k:
break
mi = min(a)
return ans
这样优化后减少了每找到一个值就需要枚举一次列表。
方法2:
每一行都按顺序报数,谁先出现0谁最弱
因为题目告诉“1 总是出现在 0 之前”
- 遍历每一行的第一列是否是0,谁是0谁最弱,记录行号,为了简化处理整行都是1的情况,我们可以在每一行末尾都添加一个0
- 检查每一行的第二列……以此循环
- 在这个过程中如过记录的数量打到k,直接return跳出即可
因为题意是说军人必定在前面,所以就有了哪一行先出现0,哪一行的战斗力就最弱。
class Solution:
def kWeakestRows(self, mat, k: int):
ans = []
column = 0
while True:
for index,row in enumerate(mat):
row.append(0)
if row[column] == 0 and index not in ans:
ans.append(index)
if len(ans) == k:
return ans
column += 1
我们首先定义一个column代表列数。然后我们看是枚举每行,检查每行的第一列是不是为0,如果是0并且这一行的行号没有在目标列表中,那么就添加该行号,然后检查目标列表长度是不是等于K,满足条件了之后就返回列表。
依次检查,检查完了第一列再检查第二列。
本题官方解答链接
官方解答中的二分查找+堆以及二分查找+快速选择有待学习。