You are given an m x n
binary matrix mat
of 1
's (representing soldiers) and 0
's (representing civilians). The soldiers are positioned in front of the civilians. That is, all the 1
's will appear to the left of all the 0
's in each row.
A row i
is weaker than a row j
if one of the following is true:
i
is less than the number of soldiers in row j
.i < j
.Return the indices of the k
weakest rows in the matrix ordered from weakest to strongest.
Example 1:
Input: 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
Output: [2,0,3]
Explanation:
The number of soldiers in each row is:
- Row 0: 2
- Row 1: 4
- Row 2: 1
- Row 3: 2
- Row 4: 5
The rows ordered from weakest to strongest are [2,0,3,1,4].
Example 2:
Input: mat =
[ [1,0,0,0],
[1,1,1,1],
[1,0,0,0],
[1,0,0,0] ],
k = 2
Output: [0,2]
Explanation:
The number of soldiers in each row is:
- Row 0: 1
- Row 1: 4
- Row 2: 1
- Row 3: 1
The rows ordered from weakest to strongest are [0,2,3,1].
Constraints:
m == mat.length
n == mat[i].length
2 <= n, m <= 100
1 <= k <= m
matrix[i][j]
is either 0 or 1.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force approach to finding the weakest rows in a matrix involves directly calculating the 'strength' of each row and then sorting them. We consider every row individually without any initial assumptions. This is a straightforward, though potentially inefficient, method.
Here's how the algorithm would work step-by-step:
def k_weakest_rows(matrix, k):
row_strengths = []
for row_index in range(len(matrix)):
soldier_count = sum(matrix[row_index])
# Store row index and its strength to maintain original order later
row_strengths.append((row_index, soldier_count))
# Sort rows based on strength, using row index as tiebreaker
row_strengths.sort(key=lambda item: (item[1], item[0]))
weakest_rows = []
for i in range(k):
# Extract the row indices to return
weakest_rows.append(row_strengths[i][0])
return weakest_rows
The fastest way to find the weakest rows is to figure out the 'strength' of each row and then efficiently pick out the weakest ones. We'll use a clever search to quickly determine row strength, then a data structure to keep track of the weakest rows without fully sorting all the rows.
Here's how the algorithm would work step-by-step:
def k_weakest_rows(matrix, k):
number_of_rows = len(matrix)
row_strengths = []
def find_first_zero(row):
left_index = 0
right_index = len(row)
while left_index < right_index:
middle_index = (left_index + right_index) // 2
if row[middle_index] == 0:
right_index = middle_index
else:
left_index = middle_index + 1
return left_index
# Calculate strength of each row using binary search
for row_index in range(number_of_rows):
row_strengths.append((find_first_zero(matrix[row_index]), row_index))
# Sort the rows based on their strengths.
row_strengths.sort()
# Extract the indices of the k weakest rows.
weakest_row_indices = [row_strengths[i][1] for i in range(k)]
return weakest_row_indices
Case | How to Handle |
---|---|
Null or empty matrix | Return an empty list immediately as there are no rows to evaluate. |
Matrix with zero columns | The sum of rows will always be zero; handle ties based on row index. |
k is zero | Return an empty list since no rows are requested. |
k is greater than the number of rows | Return all rows sorted by strength in ascending order. |
All rows have the same number of soldiers (all 0s or all 1s) | The algorithm must maintain the original order of the rows as tie-breaker. |
Matrix with only one row | Return a list containing only the index 0 if k >= 1, otherwise empty list. |
Large matrix dimensions leading to potential memory issues (e.g., exceeding memory limits when storing row strengths) | Employ a heap-based solution with a fixed size of k to minimize memory usage. |
Integer overflow when calculating row strength (number of 1s) | Ensure that the matrix values are only 0 or 1, preventing overflow in calculating the sum. |