-
Notifications
You must be signed in to change notification settings - Fork 2
feat(arrays, puzzles, matrix): lucky number in a matrix #115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,146 @@ | ||
| # Lucky Numbers in a Matrix | ||
|
|
||
| Given an m × n matrix of distinct numbers, return the lucky number in the matrix. | ||
|
|
||
| > A lucky number is an element of the matrix such that it is the smallest element in its row and largest in its column. | ||
|
|
||
| Constraints | ||
|
|
||
| - m = `matrix.length` | ||
| - n = `matrix[i].length` | ||
| - 1 <= m, n <= 50 | ||
| - 1 <= `matrix[i][j]` <= 10^5 | ||
| - All elements in the matrix are distinct. | ||
|
|
||
| ## Examples | ||
|
|
||
|  | ||
|  | ||
|  | ||
|
|
||
| ## Solution: Greedy | ||
|
|
||
| The core idea behind the solution is to recognize that there can be, at most, one lucky number in the matrix. This is | ||
| proven by contradiction, as having two such numbers would violate the unique conditions for being a lucky number. | ||
|
|
||
| > **Proof by contradiction:** | ||
| > | ||
| > 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 | ||
| > row and the largest value in its column, making it a lucky number. | ||
| > Now, assume another integer y exists in row r2 and column c2. For the sake of argument, let’s assume y is also a | ||
| > lucky number, meaning it is the smallest value in its row and the largest in its column. | ||
| > We assess these assumptions using the following steps: | ||
| > | ||
| > 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 | ||
| > integer at position (r2,c2) as `a` | ||
| > - Then, `y` < `a` because `y` is the minimum in its row | ||
| > - Then, `x` > `a` because `x` is the maximum in it column. | ||
| > | ||
| > Therefore `y` < `x` | ||
| > | ||
| > 2. Next, let's consider the integer at position (r1, c2), which we'll call `b` | ||
| > - Then, `y` > `b` because `y` is the maximum in its column | ||
| > - Then, `x` < `b` because `x` is the minimum in its row | ||
| > | ||
| > Therefore `y` > `x` | ||
| > | ||
| > This leads to a contradiction, as we deduced `y<x` and `y>x`. This inconsistency implies that our initial assumption— | ||
| > that y is a lucky number—is incorrect. Therefore, only x can be the lucky number in this configuration. | ||
| > | ||
| > Visually, this looks like this: | ||
| > | ||
| >  | ||
|
|
||
| This problem can be solved using a greedy algorithm that analyzes the matrix row by row and column by column. | ||
|
|
||
| We start by iterating over the rows to find the minimum values. Out of those minimum values, we choose the largest | ||
| minimum value and store it in r_largest_min. Similarly, we calculate the maximum values in columns and after finding | ||
| all the largest values, we choose the smallest of them and store them in c_smallest_max. Once we have found the values | ||
| in both rows and columns, we match them to see if they are the same. If they are, we return either of the values; | ||
| r_largest_min or c_smallest_max. Otherwise if now matching value is found, we return an empty matrix. | ||
|
|
||
| Following are the detailed steps of the algorithm that we have just discussed: | ||
|
|
||
| 1. We define two variables, r_largest_min and c_smallest_max: | ||
|
|
||
| - r_largest_min is set to negative infinity (float('-inf')) to ensure any row’s minimum value can be updated. | ||
| - c_smallest_max is set to positive infinity (float('inf')) to ensure any column’s maximum value can be updated. | ||
|
|
||
| 2. For each row in the matrix: | ||
|
|
||
| - We calculate the minimum value of the row (r_min). | ||
| - Then, we update r_largest_min to the maximum of r_largest_min and r_min. | ||
| - The steps above ensure we consider only minimum values in their rows, narrowing the candidate set for a lucky number. | ||
|
|
||
| 3. For each column in the matrix: | ||
|
|
||
| - We calculate the maximum value of the column (c_max) by iterating over all rows. | ||
| - Next, we update c_max_min to the minimum of c_smallest_max and c_max. | ||
| - The above steps ensure we consider only maximum values in their columns, further narrowing the candidate set for a | ||
| lucky number. | ||
|
|
||
| 4. Finally, we compare whether r_largest_min equals c_smallest_max. If TRUE, we return the value stored in [r_largest_min]. | ||
| Otherwise, we return an empty array []. The comparison ensures that the identified value satisfies both conditions of | ||
| being the minimum in its row and the maximum in its column, making it a valid lucky number. | ||
|
|
||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|
|
||
| ### Time Complexity | ||
|
|
||
| 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 | ||
| rows in the matrix. | ||
|
|
||
| ### Space Complexity | ||
|
|
||
| The solution’s space complexity is O(1) as no extra space is required apart from the few variables. | ||
|
|
||
| ## Solution: Simulation | ||
|
|
||
| We are given a matrix of size MXN with distinct integers. We need to return the list of lucky numbers in the matrix. | ||
| An integer in the matrix is lucky if it is the maximum integer in its column and it is the minimum value in its row. | ||
|
|
||
| In this approach, we will simulate the process by iterating over each integer in the matrix, checking if it is the | ||
| maximum in its row and the minimum in its column. If it meets both criteria, we will add it to the list of lucky numbers, | ||
| luckyNumbers. | ||
|
|
||
| The naive approach to check the criteria for each integer involves iterating over each integer in the current row and | ||
| column to verify the minimum and maximum criteria, requiring M+N operations per integer. A more efficient method is to | ||
| precompute the minimum of each row and the maximum of each column before processing the matrix. This allows us to check | ||
| the criteria for each integer in constant time. We iterate over each row to store the minimum in rowMin and each column | ||
| to store the maximum in colMax. | ||
|
|
||
| ### Algorithm | ||
|
|
||
| 1. Iterate over each row and store the minimum of the ith row at the ith position in the list rowMin. | ||
| 2. Iterate over each column and store the maximum of the ith column at the ith position in the list colMax. | ||
| 3. Iterate over each integer in the matrix and for each integer at (i, j), check if the integer is equal to rowMin[i] | ||
| and colMax[j]. If yes, add it to the list luckyNumbers. | ||
| 4. Return luckyNumbers. | ||
|
|
||
| ### Complexity Analysis | ||
|
|
||
| Here, N is the number of rows in the matrix and M is the number of columns in the matrix. | ||
|
|
||
| #### Time complexity: O(N*M). | ||
|
|
||
| To store the maximum of each row, we require N*M operations and the same for strong the maximum of each column. In the | ||
| end, to find the lucky numbers we again iterate over each integer. Hence, the total time complexity is equal to O(N*M). | ||
|
|
||
| #### Space complexity: O(N+M). | ||
|
|
||
| We require two lists, rowMin and colMax of size N and M respectively. Hence the total space complexity is equal to O(N+M). | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| from typing import List | ||
|
|
||
|
|
||
| def lucky_numbers(matrix: List[List[int]]) -> List[int]: | ||
| """ | ||
| This function takes a matrix as input and returns a list containing the lucky number(s) if they exist. | ||
|
|
||
| A lucky number is a number that is the maximum of the minimum values from each row and the minimum of the maximum | ||
| values from each column. | ||
|
|
||
| If a lucky number exists, the function returns a list containing that number. Otherwise, it returns an empty list. | ||
|
|
||
| Time Complexity: O(m * n) where m is the number of columns and n is the number of rows in the matrix. | ||
| Space Complexity: O(1) as we are using a constant amount of extra space. | ||
|
|
||
BrianLusina marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Args: | ||
| matrix (List[List[int]]): The input matrix. | ||
|
|
||
| Returns: | ||
| List[int]: A list containing the lucky number(s) if they exist, otherwise an empty list. | ||
| """ | ||
| row_length = len(matrix) | ||
| col_length = len(matrix[0]) | ||
|
|
||
| # initialize a variable to keep track of the maximum of the minimum values from each row | ||
| r_largest_min = float("-inf") | ||
|
|
||
| # We start by iterating over the rows to find the minimum values. Out of those minimum values, we choose the | ||
| # largest minimum value and store it in r_largest_min | ||
| for i in range(row_length): | ||
| # find the minimum value in current row | ||
| row_min = min(matrix[i]) | ||
| # update r_largest_min to be the maximum of current r_largest_min and the current row minimum | ||
| r_largest_min = max(r_largest_min, row_min) | ||
|
|
||
| # initialize a variable to keep track of the minimum of the maximum values from each column | ||
| c_smallest_max = float("inf") | ||
| # Similarly, we calculate the maximum values in columns and after finding all the largest values, we choose the | ||
| # smallest of them and store them in c_smallest_max | ||
| for c in range(col_length): | ||
| # find the maximum value in the current row | ||
| col_max = max(matrix[r][c] for r in range(row_length)) | ||
| # update c_smallest_max to be the minium of the current c_smallest_max and the current column maximum | ||
| c_smallest_max = min(c_smallest_max, col_max) | ||
|
|
||
| # If they are, we return either of the values; r_largest_min or c_smallest_max. Otherwise if now matching value is | ||
| # found, we return an empty matrix. | ||
|
|
||
| # check if the maximum of row minima is equal to the minimum of column maxima | ||
| if r_largest_min == c_smallest_max: | ||
| # if they are equal, return a list containing the luky number | ||
| return [r_largest_min] | ||
| # Otherwise, return an empty list indicating no luky number exists | ||
| return [] | ||
|
|
||
|
|
||
| def lucky_numbers_simulation(matrix: List[List[int]]) -> List[int]: | ||
| """ | ||
| This function takes a matrix as input and returns a list containing all the lucky number(s) if they exist. | ||
|
|
||
| A lucky number is a number that is the maximum of the minimum values from each row and the minimum of the maximum | ||
| values from each column. | ||
|
|
||
| The function first calculates the minimum values from each row and the maximum values from each column, then compares | ||
| these two lists to find the lucky number(s). | ||
|
|
||
| Time Complexity: O(m * n) where m is the number of columns and n is the number of rows in the matrix. | ||
| Space Complexity: O(m + n) as we are using two lists of size m and n respectively. | ||
|
|
||
| Args: | ||
| matrix (List[List[int]]): The input matrix. | ||
|
|
||
| Returns: | ||
| List[int]: A list containing all the lucky number(s) if they exist, otherwise an empty list. | ||
| """ | ||
| row_length = len(matrix) | ||
| col_length = len(matrix[0]) | ||
|
|
||
| row_min = [] | ||
| for i in range(row_length): | ||
| r_min = float('inf') | ||
| for j in range(col_length): | ||
| r_min = min(r_min, matrix[i][j]) | ||
| row_min.append(r_min) | ||
|
|
||
| col_max = [] | ||
| for i in range(col_length): | ||
| c_max = float('-inf') | ||
| for j in range(row_length): | ||
| c_max = max(c_max, matrix[j][i]) | ||
| col_max.append(c_max) | ||
|
|
||
| result = [] | ||
| for i in range(row_length): | ||
| for j in range(col_length): | ||
| if matrix[i][j] == row_min[i] and matrix[i][j] == col_max[j]: | ||
| result.append(matrix[i][j]) | ||
|
|
||
| return result | ||
Binary file added
BIN
+31.4 KB
...cky_numbers_in_a_matrix/images/examples/lucky_numbers_in_a_matrix_example_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+29.1 KB
...cky_numbers_in_a_matrix/images/examples/lucky_numbers_in_a_matrix_example_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+27.5 KB
...cky_numbers_in_a_matrix/images/examples/lucky_numbers_in_a_matrix_example_3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+20.1 KB
...y_numbers_in_a_matrix/images/solutions/lucky_numbers_in_a_matrix_solution_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+37.2 KB
..._numbers_in_a_matrix/images/solutions/lucky_numbers_in_a_matrix_solution_10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+38.1 KB
..._numbers_in_a_matrix/images/solutions/lucky_numbers_in_a_matrix_solution_11.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+37.6 KB
..._numbers_in_a_matrix/images/solutions/lucky_numbers_in_a_matrix_solution_12.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+38.6 KB
..._numbers_in_a_matrix/images/solutions/lucky_numbers_in_a_matrix_solution_13.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+38 KB
..._numbers_in_a_matrix/images/solutions/lucky_numbers_in_a_matrix_solution_14.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+45.9 KB
..._numbers_in_a_matrix/images/solutions/lucky_numbers_in_a_matrix_solution_15.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+29.1 KB
..._numbers_in_a_matrix/images/solutions/lucky_numbers_in_a_matrix_solution_16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+27.1 KB
...y_numbers_in_a_matrix/images/solutions/lucky_numbers_in_a_matrix_solution_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+34.5 KB
...y_numbers_in_a_matrix/images/solutions/lucky_numbers_in_a_matrix_solution_3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+34.5 KB
...y_numbers_in_a_matrix/images/solutions/lucky_numbers_in_a_matrix_solution_4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+32.9 KB
...y_numbers_in_a_matrix/images/solutions/lucky_numbers_in_a_matrix_solution_5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+33.9 KB
...y_numbers_in_a_matrix/images/solutions/lucky_numbers_in_a_matrix_solution_6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+32.4 KB
...y_numbers_in_a_matrix/images/solutions/lucky_numbers_in_a_matrix_solution_7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+38.1 KB
...y_numbers_in_a_matrix/images/solutions/lucky_numbers_in_a_matrix_solution_8.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+30.2 KB
...y_numbers_in_a_matrix/images/solutions/lucky_numbers_in_a_matrix_solution_9.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+234 KB
...y_numbers_in_a_matrix/images/solutions/lucky_numbers_proof_of_contradiction.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
73 changes: 73 additions & 0 deletions
73
puzzles/arrays/lucky_numbers_in_a_matrix/test_lucky_numbers_in_a_matrix.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| import unittest | ||
| from typing import List | ||
| from parameterized import parameterized | ||
| from puzzles.arrays.lucky_numbers_in_a_matrix import lucky_numbers, lucky_numbers_simulation | ||
|
|
||
|
|
||
| class LuckyNumbersInAMatrixTestCase(unittest.TestCase): | ||
|
|
||
| @parameterized.expand( | ||
| [ | ||
| ([[3, 7, 8], [9, 11, 13], [15, 16, 17]], [15]), | ||
| ([[1, 2, 3], [4, 5, 6], [7, 8, 9]], [7]), | ||
| ( | ||
| [ | ||
| [10, 20, 30, 40], | ||
| [5, 25, 35, 50], | ||
| [60, 70, 80, 90], | ||
| [100, 110, 120, 130], | ||
| ], | ||
| [100], | ||
| ), | ||
| ( | ||
| [[12, 18, 23, 50], [5, 16, 25, 45], [4, 15, 26, 48], [3, 14, 27, 60]], | ||
| [12], | ||
| ), | ||
| ([[5]], [5]), | ||
| ([[30, 20, 10], [40, 50, 60], [70, 80, 90]], [70]), | ||
| ([[5, 1, 9], [10, 8, 2], [7, 3, 6]], []), | ||
| ([[22, 11], [88, 77], [55, 44]], [77]), | ||
| ([[1,10,4,2],[9,3,8,7],[15,16,17,12]], [12]), | ||
| ([[7,8],[1,2]], [7]), | ||
| ] | ||
| ) | ||
| def test_lucky_numbers_in_matrix( | ||
| self, matrix: List[List[int]], expected: List[int] | ||
| ): | ||
| actual = lucky_numbers(matrix) | ||
| self.assertEqual(expected, actual) | ||
|
|
||
| @parameterized.expand( | ||
| [ | ||
| ([[3, 7, 8], [9, 11, 13], [15, 16, 17]], [15]), | ||
| ([[1, 2, 3], [4, 5, 6], [7, 8, 9]], [7]), | ||
| ( | ||
| [ | ||
| [10, 20, 30, 40], | ||
| [5, 25, 35, 50], | ||
| [60, 70, 80, 90], | ||
| [100, 110, 120, 130], | ||
| ], | ||
| [100], | ||
| ), | ||
| ( | ||
| [[12, 18, 23, 50], [5, 16, 25, 45], [4, 15, 26, 48], [3, 14, 27, 60]], | ||
| [12], | ||
| ), | ||
| ([[5]], [5]), | ||
| ([[30, 20, 10], [40, 50, 60], [70, 80, 90]], [70]), | ||
| ([[5, 1, 9], [10, 8, 2], [7, 3, 6]], []), | ||
| ([[22, 11], [88, 77], [55, 44]], [77]), | ||
| ([[1,10,4,2],[9,3,8,7],[15,16,17,12]], [12]), | ||
| ([[7,8],[1,2]], [7]), | ||
| ] | ||
| ) | ||
| def test_lucky_numbers_in_matrix_simulation( | ||
| self, matrix: List[List[int]], expected: List[int] | ||
| ): | ||
| actual = lucky_numbers_simulation(matrix) | ||
| self.assertEqual(expected, actual) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| unittest.main() |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.