Skip to content

Commit 503db60

Browse files
committed
feat(arrays, puzzles, matrix): lucky number in matrix
1 parent 6da8745 commit 503db60

22 files changed

+199
-0
lines changed
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Lucky Numbers in a Matrix
2+
3+
Given an m × n matrix of distinct numbers, return the lucky number in the matrix.
4+
5+
> A lucky number is an element of the matrix such that it is the smallest element in its row and largest in its column.
6+
7+
Constraints
8+
9+
- m = `matrix.length`
10+
- n = `matrix[i].length`
11+
- 1 <= m, n <= 50
12+
- 1 <= `matrix[i][j]` <= 10^5
13+
- All elements in the matrix are distinct.
14+
15+
## Examples
16+
17+
![Example 1](./images/examples/lucky_numbers_in_a_matrix_example_1.png)
18+
![Example 2](./images/examples/lucky_numbers_in_a_matrix_example_2.png)
19+
![Example 3](./images/examples/lucky_numbers_in_a_matrix_example_3.png)
20+
21+
## Solution
22+
23+
The core idea behind the solution is to recognize that there can be, at most, one lucky number in the matrix. This is
24+
proven by contradiction, as having two such numbers would violate the unique conditions for being a lucky number.
25+
26+
> **Proof by contradiction:**
27+
>
28+
> Suppose we have an integer x located at row r1 and column c1 in a matrix. The integer x is the smallest value in its
29+
> row and the largest value in its column, making it a lucky number.
30+
> Now, assume another integer y exists in row r2 and column c2. For the sake of argument, let’s assume y is also a
31+
> lucky number, meaning it is the smallest value in its row and the largest in its column.
32+
> We assess these assumptions using the following steps:
33+
>
34+
> 1. As `y` is a lucky number, the smallest value is in row r2 and the largest value is in column c2. Let’s denote the
35+
> integer at position (r2,c2) as `a`
36+
> - Then, `y` < `a` because `y` is the minimum in its row
37+
> - Then, `x` > `a` because `x` is the maximum in it column.
38+
>
39+
> Therefore `y` < `x`
40+
>
41+
> 2. Next, let's consider the integer at position (r1, c2), which we'll call `b`
42+
> - Then, `y` > `b` because `y` is the maximum in its column
43+
> - Then, `x` < `b` because `x` is the minimum in its row
44+
>
45+
> Therefore `y` > `x`
46+
>
47+
> This leads to a contradiction, as we deduced `y<x` and `y>x`. This inconsistency implies that our initial assumption—
48+
> that y is a lucky number—is incorrect. Therefore, only x can be the lucky number in this configuration.
49+
50+
This problem can be solved using a greedy algorithm that analyzes the matrix row by row and column by column.
51+
52+
We start by iterating over the rows to find the minimum values. Out of those minimum values, we choose the largest
53+
minimum value and store it in r_largest_min. Similarly, we calculate the maximum values in columns and after finding
54+
all the largest values, we choose the smallest of them and store them in c_smallest_max. Once we have found the values
55+
in both rows and columns, we match them to see if they are the same. If they are, we return either of the values;
56+
r_largest_min or c_smallest_max. Otherwise if now matching value is found, we return an empty matrix.
57+
58+
Following are the detailed steps of the algorithm that we have just discussed:
59+
60+
1. We define two variables, r_largest_min and c_smallest_max:
61+
62+
- r_largest_min is set to negative infinity (float('-inf')) to ensure any row’s minimum value can be updated.
63+
- c_smallest_max is set to positive infinity (float('inf')) to ensure any column’s maximum value can be updated.
64+
65+
2. For each row in the matrix:
66+
67+
- We calculate the minimum value of the row (r_min).
68+
- Then, we update r_largest_min to the maximum of r_largest_min and r_min.
69+
- The steps above ensure we consider only minimum values in their rows, narrowing the candidate set for a lucky number.
70+
71+
3. For each column in the matrix:
72+
73+
- We calculate the maximum value of the column (c_max) by iterating over all rows.
74+
- Next, we update c_max_min to the minimum of c_smallest_max and c_max.
75+
- The above steps ensure we consider only maximum values in their columns, further narrowing the candidate set for a lucky number.
76+
77+
4. Finally, we compare whether r_largest_min equals c_smallest_max. If TRUE, we return the value stored in [r_largest_min].
78+
Otherwise, we return an empty array []. The comparison ensures that the identified value satisfies both conditions of
79+
being the minimum in its row and the maximum in its column, making it a valid lucky number.
80+
81+
![Solution 1](./images/solutions/lucky_numbers_in_a_matrix_solution_1.png)
82+
![Solution 2](./images/solutions/lucky_numbers_in_a_matrix_solution_2.png)
83+
![Solution 3](./images/solutions/lucky_numbers_in_a_matrix_solution_3.png)
84+
![Solution 4](./images/solutions/lucky_numbers_in_a_matrix_solution_4.png)
85+
![Solution 5](./images/solutions/lucky_numbers_in_a_matrix_solution_5.png)
86+
![Solution 6](./images/solutions/lucky_numbers_in_a_matrix_solution_6.png)
87+
![Solution 7](./images/solutions/lucky_numbers_in_a_matrix_solution_7.png)
88+
![Solution 8](./images/solutions/lucky_numbers_in_a_matrix_solution_8.png)
89+
![Solution 9](./images/solutions/lucky_numbers_in_a_matrix_solution_9.png)
90+
![Solution 10](./images/solutions/lucky_numbers_in_a_matrix_solution_10.png)
91+
![Solution 11](./images/solutions/lucky_numbers_in_a_matrix_solution_11.png)
92+
![Solution 12](./images/solutions/lucky_numbers_in_a_matrix_solution_12.png)
93+
![Solution 13](./images/solutions/lucky_numbers_in_a_matrix_solution_13.png)
94+
![Solution 14](./images/solutions/lucky_numbers_in_a_matrix_solution_14.png)
95+
![Solution 15](./images/solutions/lucky_numbers_in_a_matrix_solution_15.png)
96+
![Solution 16](./images/solutions/lucky_numbers_in_a_matrix_solution_16.png)
97+
98+
### Time Complexity
99+
100+
The time complexity of the solution is O(m×n), where m is the number of columns in the matrix and n is the number of
101+
rows in the matrix.
102+
103+
### Space Complexity
104+
105+
The solution’s space complexity is O(1) as no extra space is required apart from the few variables.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
from typing import List
2+
3+
4+
def lucky_numbers(matrix: List[List[int]]) -> List[int]:
5+
"""
6+
This function takes a matrix as input and returns a list containing the lucky number(s) if they exist.
7+
8+
A lucky number is a number that is the maximum of the minimum values from each row and the minimum of the maximum
9+
values from each column.
10+
11+
If a lucky number exists, the function returns a list containing that number. Otherwise, it returns an empty list.
12+
13+
Time Complexity: O(m * n) where m is the number of columns and n is the number of rows in the matrix.
14+
Space Complexity: O(1) as we are using a constant amount of extra space.
15+
16+
Args:
17+
matrix (List[List[int]]): The input matrix.
18+
19+
Returns:
20+
List[int]: A list containing the lucky number(s) if they exist, otherwise an empty list.
21+
"""
22+
row_length = len(matrix)
23+
col_length = len(matrix[0])
24+
25+
# initialize a variable to keep track of the maximum of the minimum values from each row
26+
r_largest_min = float("-inf")
27+
28+
# We start by iterating over the rows to find the minimum values. Out of those minimum values, we choose the
29+
# largest minimum value and store it in r_largest_min
30+
for i in range(row_length):
31+
# find the minimum value in current row
32+
row_min = min(matrix[i])
33+
# update r_largest_min to be the maximum of current r_largest_min and the current row minimum
34+
r_largest_min = max(r_largest_min, row_min)
35+
36+
# initialize a variable to keep track of the minimum of the maximum values from each column
37+
c_smallest_max = float("inf")
38+
# Similarly, we calculate the maximum values in columns and after finding all the largest values, we choose the
39+
# smallest of them and store them in c_smallest_max
40+
for c in range(col_length):
41+
# find the maximum value in the current row
42+
col_max = max(matrix[r][c] for r in range(row_length))
43+
# update c_smallest_max to be the minium of the current c_smallest_max and the current column maximum
44+
c_smallest_max = min(c_smallest_max, col_max)
45+
46+
# If they are, we return either of the values; r_largest_min or c_smallest_max. Otherwise if now matching value is
47+
# found, we return an empty matrix.
48+
49+
# check if the maximum of row minima is equal to the minimum of column maxima
50+
if r_largest_min == c_smallest_max:
51+
# if they are equal, return a list containing the luky number
52+
return [r_largest_min]
53+
# Otherwise, return an empty list indicating no luky number exists
54+
return []
31.4 KB
Loading
29.1 KB
Loading
27.5 KB
Loading
20.1 KB
Loading
37.2 KB
Loading
38.1 KB
Loading
37.6 KB
Loading
38.6 KB
Loading

0 commit comments

Comments
 (0)