{x}
blog image

The K Weakest Rows in a Matrix

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:

  • The number of soldiers in row i is less than the number of soldiers in row j.
  • Both rows have the same number of soldiers and 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.

Solution Explanation

The problem asks to find the indices of the k weakest rows in a binary matrix. A row is weaker than another if it has fewer soldiers (1s) or, if they have the same number of soldiers, it has a smaller index.

The solutions use different approaches to achieve this:

Approach 1: Binary Search + Sorting

This approach efficiently determines the number of soldiers in each row using binary search and then sorts the rows based on the number of soldiers and their indices.

Time Complexity Analysis:

  • Binary Search: The binary search to find the number of soldiers in each row takes O(log n) time, where n is the number of columns. Since we do this for each of the m rows, this part contributes O(m log n) to the overall time complexity.
  • Sorting: Sorting the rows takes O(m log m) time, where m is the number of rows.

Therefore, the overall time complexity of this approach is O(m log n + m log m). In the case where m and n are of similar magnitude, this simplifies to O(m log m).

Space Complexity Analysis:

The space complexity is dominated by the auxiliary array used for sorting and storing intermediate results which is O(m).

Code Explanation (Python):

class Solution:
    def kWeakestRows(self, mat: List[List[int]], k: int) -> List[int]:
        m, n = len(mat), len(mat[0])
        ans = [n - bisect_right(row[::-1], 0) for row in mat] #Efficiently count soldiers using bisect_right
        idx = list(range(m))
        idx.sort(key=lambda i: ans[i]) #Sort indices based on soldier count
        return idx[:k]

The code first calculates the number of soldiers in each row using bisect_right. bisect_right finds the insertion point for 0 in the reversed row, effectively giving the number of 1s. Then, it creates a list of indices and sorts them based on the number of soldiers in each corresponding row. Finally, it returns the first k indices from the sorted list.

Approach 2: Counting Soldiers and Sorting (Other Languages)

The Java, C++, Go, and TypeScript solutions employ similar strategies:

  1. Count Soldiers: Iterate through each row and count the number of soldiers (1s). This can be done with a simple loop or more optimized techniques depending on the language.
  2. Store Row Information: Create a data structure (e.g., an array of pairs, a list of tuples) to store the number of soldiers and the row index for each row.
  3. Sort: Sort the data structure based on the number of soldiers (primary key) and row index (secondary key) to handle ties.
  4. Return Top k: Select the top k rows from the sorted data structure.

The time complexity is O(m log m) due to sorting and O(m) for counting and storing the information. The space complexity is O(m).

Note: The specific implementation details (using arrays, lists, or other data structures) differ slightly across languages to leverage the language's features efficiently. The core algorithm remains the same across the different languages presented.