🧠
Precompute Row Minimums and Column Maximums
💡 This approach improves efficiency by precomputing the minimum value in each row and the maximum value in each column, avoiding repeated scanning.
Intuition
If we know the minimum of each row and maximum of each column, a lucky number must be an element equal to both its row minimum and column maximum.
Algorithm
- Compute an array of minimum values for each row.
- Compute an array of maximum values for each column.
- Iterate over the matrix and collect elements that equal both their row minimum and column maximum.
💡 Precomputing reduces repeated work, making the solution more efficient and easier to understand.
from typing import List
def luckyNumbers(matrix: List[List[int]]) -> List[int]:
m, n = len(matrix), len(matrix[0])
row_mins = [min(row) for row in matrix]
col_maxs = [max(matrix[i][j] for i in range(m)) for j in range(n)]
result = []
for i in range(m):
for j in range(n):
if matrix[i][j] == row_mins[i] and matrix[i][j] == col_maxs[j]:
result.append(matrix[i][j])
return result
# Driver code
if __name__ == '__main__':
mat = [[3,7,8],[9,11,13],[15,16,17]]
print(luckyNumbers(mat)) # Output: [15]
Line Notes
row_mins = [min(row) for row in matrix]Precompute minimum of each row once
col_maxs = [max(matrix[i][j] for i in range(m)) for j in range(n)]Precompute maximum of each column once
for i in range(m):Iterate over rows to check candidates
if matrix[i][j] == row_mins[i] and matrix[i][j] == col_maxs[j]Check if element matches both conditions
import java.util.*;
public class LuckyNumbers {
public static List<Integer> luckyNumbers(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
int[] rowMins = new int[m];
int[] colMaxs = new int[n];
Arrays.fill(rowMins, Integer.MAX_VALUE);
Arrays.fill(colMaxs, Integer.MIN_VALUE);
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
rowMins[i] = Math.min(rowMins[i], matrix[i][j]);
colMaxs[j] = Math.max(colMaxs[j], matrix[i][j]);
}
}
List<Integer> result = new ArrayList<>();
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (matrix[i][j] == rowMins[i] && matrix[i][j] == colMaxs[j]) {
result.add(matrix[i][j]);
}
}
}
return result;
}
public static void main(String[] args) {
int[][] mat = {{3,7,8},{9,11,13},{15,16,17}};
System.out.println(luckyNumbers(mat)); // Output: [15]
}
}
Line Notes
int[] rowMins = new int[m];Array to store minimums per row
Arrays.fill(rowMins, Integer.MAX_VALUE);Initialize row minimums to max value for comparison
rowMins[i] = Math.min(rowMins[i], matrix[i][j]);Update row minimum while scanning
if (matrix[i][j] == rowMins[i] && matrix[i][j] == colMaxs[j])Check if element is lucky number
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> luckyNumbers(vector<vector<int>>& matrix) {
int m = matrix.size(), n = matrix[0].size();
vector<int> rowMins(m, INT_MAX);
vector<int> colMaxs(n, INT_MIN);
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
rowMins[i] = min(rowMins[i], matrix[i][j]);
colMaxs[j] = max(colMaxs[j], matrix[i][j]);
}
}
vector<int> result;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (matrix[i][j] == rowMins[i] && matrix[i][j] == colMaxs[j]) {
result.push_back(matrix[i][j]);
}
}
}
return result;
}
int main() {
vector<vector<int>> mat = {{3,7,8},{9,11,13},{15,16,17}};
vector<int> res = luckyNumbers(mat);
for (int num : res) cout << num << " ";
cout << endl; // Output: 15
return 0;
}
Line Notes
vector<int> rowMins(m, INT_MAX);Initialize row minimums with max int
rowMins[i] = min(rowMins[i], matrix[i][j]);Update minimum for each row element
vector<int> colMaxs(n, INT_MIN);Initialize column maximums with min int
if (matrix[i][j] == rowMins[i] && matrix[i][j] == colMaxs[j])Check if element is lucky number
function luckyNumbers(matrix) {
const m = matrix.length, n = matrix[0].length;
const rowMins = Array(m).fill(Infinity);
const colMaxs = Array(n).fill(-Infinity);
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
rowMins[i] = Math.min(rowMins[i], matrix[i][j]);
colMaxs[j] = Math.max(colMaxs[j], matrix[i][j]);
}
}
const result = [];
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
if (matrix[i][j] === rowMins[i] && matrix[i][j] === colMaxs[j]) {
result.push(matrix[i][j]);
}
}
}
return result;
}
// Test
const mat = [[3,7,8],[9,11,13],[15,16,17]];
console.log(luckyNumbers(mat)); // Output: [15]
Line Notes
const rowMins = Array(m).fill(Infinity);Initialize row minimums to Infinity for comparison
rowMins[i] = Math.min(rowMins[i], matrix[i][j]);Update row minimum while scanning
const colMaxs = Array(n).fill(-Infinity);Initialize column maximums to -Infinity
if (matrix[i][j] === rowMins[i] && matrix[i][j] === colMaxs[j])Check if element is lucky number
TimeO(m * n)
SpaceO(m + n)
We scan the matrix twice: once to compute row minimums and column maximums, and once to find lucky numbers, resulting in linear time relative to matrix size.
💡 For a 50x50 matrix, this means about 2 * 2500 = 5000 operations, which is efficient and fast.
Interview Verdict: Accepted and efficient
This approach is optimal for the problem constraints and is the recommended solution in interviews.