|
1 | 1 | /* |
2 | 2 | * Task: Determine whether a target value exists in a row/column-sorted matrix. |
3 | 3 | * |
4 | | - * Matrix Value Search |
| 4 | + * MATRIX VALUE SEARCH |
5 | 5 | * |
6 | | - * Given a matrix where each row and each column is sorted in ascending order, |
7 | | - * determine if a given target value exists within the matrix. |
| 6 | + * The matrix has the following properties: |
| 7 | + * - Each row is sorted left-to-right |
| 8 | + * - Each column is sorted top-to-bottom |
8 | 9 | * |
9 | | - * Constraints and Expectations: |
10 | | - * - Each row is sorted left-to-right. |
11 | | - * - Each column is sorted top-to-bottom. |
12 | | - * - The task is to implement two solutions: |
13 | | - * 1. A Simple (Divide and Conquer) Approach: Uses recursion to narrow down |
14 | | - * the search space. |
15 | | - * 2. An Optimal (Staircase) Approach: Iteratively searches from the top-right |
16 | | - * corner. |
17 | | - * - An alternative brute-force solution is also provided for educational |
18 | | - * comparison. |
19 | | - * |
20 | | - * ASCII Illustration of the Matrix: |
21 | | - * +----+----+----+----+ |
22 | | - * | 1 | 2 | 8 | 9 | |
23 | | - * +----+----+----+----+ |
24 | | - * | 2 | 4 | 9 | 12 | |
25 | | - * +----+----+----+----+ |
26 | | - * | 4 | 7 | 10 | 13 | |
27 | | - * +----+----+----+----+ |
28 | | - * | 6 | 8 | 11 | 15 | |
29 | | - * +----+----+----+----+ |
30 | | - * |
31 | | - * Example: |
32 | | - * Input: Matrix as shown above, Target = 7 |
33 | | - * Output: true |
34 | | - * Explanation: The value 7 is located at row 3, column 2 (0-indexed) of the |
35 | | - * matrix. |
| 10 | + * Example matrix: |
| 11 | + * { 1, 2, 8, 9 } |
| 12 | + * { 2, 4, 9, 12 } |
| 13 | + * { 4, 7, 10, 13 } |
| 14 | + * { 6, 8, 11, 15 } |
36 | 15 | */ |
37 | 16 |
|
38 | | -#include <algorithm> |
39 | 17 | #include <iostream> |
40 | 18 | #include <string> |
41 | 19 | #include <vector> |
42 | 20 |
|
43 | | -// Simple (Divide and Conquer) Solution |
44 | | -// Recursive approach: divides the matrix into submatrices based on the middle |
45 | | -// element. Average complexity may be better than brute-force, though worst-case |
46 | | -// may involve overlapping searches. |
47 | | -bool simpleSolutionHelper(const std::vector<std::vector<int>> &matrix, |
48 | | - int value, int row1, int col1, int row2, int col2) { |
49 | | - if (row1 > row2 || col1 > col2) |
50 | | - return false; |
51 | | - |
52 | | - // If target is outside the current submatrix's range, skip search. |
53 | | - if (value < matrix[row1][col1] || value > matrix[row2][col2]) |
54 | | - return false; |
55 | | - |
56 | | - // Directly check boundaries. |
57 | | - if (value == matrix[row1][col1] || value == matrix[row2][col2]) |
58 | | - return true; |
59 | | - |
60 | | - int midRow = (row1 + row2) / 2; |
61 | | - int midCol = (col1 + col2) / 2; |
62 | | - |
63 | | - if (matrix[midRow][midCol] == value) |
64 | | - return true; |
65 | | - |
66 | | - if (value < matrix[midRow][midCol]) { |
67 | | - // Exclude the bottom-right quadrant. |
68 | | - return simpleSolutionHelper(matrix, value, row1, col1, midRow, |
69 | | - midCol - 1) || |
70 | | - simpleSolutionHelper(matrix, value, row1, midCol, midRow - 1, |
71 | | - col2) || |
72 | | - simpleSolutionHelper(matrix, value, midRow + 1, col1, row2, |
73 | | - midCol - 1); |
| 21 | +// ----------------------- 1) Simple (Brute-force) Solution -------------------- |
| 22 | +// Check every element in the matrix until the target is found. |
| 23 | +// |
| 24 | +// Time Complexity: |
| 25 | +// - O(n * m), where n = rows, m = columns |
| 26 | +// |
| 27 | +// Space Complexity: |
| 28 | +// - O(1) extra space |
| 29 | +// |
| 30 | +bool searchMatrixSimple(const std::vector<std::vector<int>>& matrix, int target) { |
| 31 | + for (const auto& row : matrix) { |
| 32 | + for (int value : row) { |
| 33 | + if (value == target) return true; |
| 34 | + } |
74 | 35 | } |
75 | | - |
76 | | - // value > mid: exclude the top-left quadrant. |
77 | | - return simpleSolutionHelper(matrix, value, midRow, midCol + 1, row2, col2) || |
78 | | - simpleSolutionHelper(matrix, value, midRow + 1, col1, row2, midCol) || |
79 | | - simpleSolutionHelper(matrix, value, row1, midCol + 1, midRow - 1, |
80 | | - col2); |
81 | | -} |
82 | | - |
83 | | -bool simpleSolution(const std::vector<std::vector<int>> &matrix, int value) { |
84 | | - if (matrix.empty() || matrix.front().empty()) |
85 | | - return false; |
86 | | - return simpleSolutionHelper(matrix, value, 0, 0, |
87 | | - static_cast<int>(matrix.size()) - 1, |
88 | | - static_cast<int>(matrix[0].size()) - 1); |
| 36 | + return false; |
89 | 37 | } |
90 | 38 |
|
91 | | -// Optimal (Staircase) Solution |
92 | | -// Iterative approach starting from the top-right corner, reducing the search |
93 | | -// space at each step. Complexity: O(n + m), where n is the number of rows and m |
94 | | -// is the number of columns. |
95 | | -bool optimalSolution(const std::vector<std::vector<int>> &matrix, int value) { |
96 | | - if (matrix.empty() || matrix.front().empty()) |
97 | | - return false; |
98 | | - |
99 | | - int rows = matrix.size(), cols = matrix[0].size(); |
100 | | - int row = 0, col = cols - 1; |
101 | | - |
102 | | - while (row < rows && col >= 0) { |
103 | | - if (matrix[row][col] == value) |
| 39 | +// ----------------------- 2) Optimal (Staircase) Solution --------------------- |
| 40 | +// |
| 41 | +// - Start at the top-right corner. |
| 42 | +// - If current value > target → move left. |
| 43 | +// - If current value < target → move down. |
| 44 | +// - Eliminate one row or column at each step. |
| 45 | +// |
| 46 | +// Time Complexity: |
| 47 | +// - O(n + m) |
| 48 | +// Each step removes a row or a column from consideration. |
| 49 | +// |
| 50 | +// Space Complexity: |
| 51 | +// - O(1) extra space |
| 52 | +// |
| 53 | +bool searchMatrixOptimal(const std::vector<std::vector<int>>& matrix, |
| 54 | + int target) { |
| 55 | + if (matrix.empty() || matrix[0].empty()) return false; |
| 56 | + |
| 57 | + int rows = matrix.size(); |
| 58 | + int cols = matrix[0].size(); |
| 59 | + |
| 60 | + int r = 0; |
| 61 | + int c = cols - 1; |
| 62 | + |
| 63 | + while (r < rows && c >= 0) { |
| 64 | + if (matrix[r][c] == target) |
104 | 65 | return true; |
105 | | - else if (matrix[row][col] > value) |
106 | | - --col; |
| 66 | + else if (matrix[r][c] > target) |
| 67 | + --c; // move left |
107 | 68 | else |
108 | | - ++row; |
| 69 | + ++r; // move down |
109 | 70 | } |
110 | | - |
111 | 71 | return false; |
112 | 72 | } |
113 | 73 |
|
114 | | -// (Optional) Alternative Solution |
115 | | -// Brute-force search for educational purposes. Complexity: O(n * m) |
116 | | -bool alternativeSolution(const std::vector<std::vector<int>> &matrix, |
117 | | - int value) { |
118 | | - for (const auto &row : matrix) |
119 | | - for (const auto &elem : row) |
120 | | - if (elem == value) |
121 | | - return true; |
122 | | - return false; |
123 | | -} |
124 | | - |
125 | | -namespace { |
| 74 | +// ------------------------------ Tests (2 examples) --------------------------- |
126 | 75 | struct TestRunner { |
127 | 76 | int total = 0; |
128 | 77 | int failed = 0; |
129 | 78 |
|
130 | | - void expectEqual(bool got, bool expected, const std::string &label) { |
| 79 | + void expect(bool got, bool expected, const std::string& label) { |
131 | 80 | ++total; |
132 | 81 | if (got == expected) { |
133 | 82 | std::cout << "[PASS] " << label << "\n"; |
134 | | - return; |
| 83 | + } else { |
| 84 | + ++failed; |
| 85 | + std::cout << "[FAIL] " << label << " expected=" << std::boolalpha |
| 86 | + << expected << " got=" << got << "\n"; |
135 | 87 | } |
136 | | - ++failed; |
137 | | - std::cout << "[FAIL] " << label << " expected=" << std::boolalpha |
138 | | - << expected << " got=" << got << "\n"; |
139 | 88 | } |
140 | 89 |
|
141 | 90 | void summary() const { |
142 | | - std::cout << "Tests: " << total - failed << " passed, " << failed |
143 | | - << " failed, " << total << " total\n"; |
| 91 | + std::cout << "Tests: " << (total - failed) << " passed, " |
| 92 | + << failed << " failed, " << total << " total\n"; |
144 | 93 | } |
145 | 94 | }; |
146 | | -} // namespace |
147 | 95 |
|
148 | | -// Test cases for correctness |
149 | | -void test() { |
150 | | - std::vector<std::vector<int>> matrix{ |
151 | | - {1, 2, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15}}; |
152 | | - TestRunner runner; |
| 96 | +int main() { |
| 97 | + std::vector<std::vector<int>> matrix = { |
| 98 | + {1, 2, 8, 9}, |
| 99 | + {2, 4, 9, 12}, |
| 100 | + {4, 7, 10, 13}, |
| 101 | + {6, 8, 11, 15} |
| 102 | + }; |
153 | 103 |
|
154 | | - // Test for a value that exists in the matrix. |
155 | | - runner.expectEqual(simpleSolution(matrix, 7), true, "simple contains 7"); |
156 | | - runner.expectEqual(optimalSolution(matrix, 7), true, "optimal contains 7"); |
157 | | - runner.expectEqual(alternativeSolution(matrix, 7), true, |
158 | | - "alternative contains 7"); |
| 104 | + TestRunner t; |
159 | 105 |
|
160 | | - // Test for a value that does not exist. |
161 | | - runner.expectEqual(simpleSolution(matrix, 5), false, "simple missing 5"); |
162 | | - runner.expectEqual(optimalSolution(matrix, 5), false, "optimal missing 5"); |
163 | | - runner.expectEqual(alternativeSolution(matrix, 5), false, |
164 | | - "alternative missing 5"); |
| 106 | + // Example 1: target exists |
| 107 | + t.expect(searchMatrixSimple(matrix, 7), true, "simple: contains 7"); |
| 108 | + t.expect(searchMatrixOptimal(matrix, 7), true, "optimal: contains 7"); |
165 | 109 |
|
166 | | - // Test boundaries. |
167 | | - runner.expectEqual(simpleSolution(matrix, 1), true, "simple contains 1"); |
168 | | - runner.expectEqual(optimalSolution(matrix, 1), true, "optimal contains 1"); |
169 | | - runner.expectEqual(alternativeSolution(matrix, 1), true, |
170 | | - "alternative contains 1"); |
| 110 | + // Example 2: target does not exist |
| 111 | + t.expect(searchMatrixSimple(matrix, 5), false, "simple: missing 5"); |
| 112 | + t.expect(searchMatrixOptimal(matrix, 5), false, "optimal: missing 5"); |
171 | 113 |
|
172 | | - runner.expectEqual(simpleSolution(matrix, 15), true, "simple contains 15"); |
173 | | - runner.expectEqual(optimalSolution(matrix, 15), true, "optimal contains 15"); |
174 | | - runner.expectEqual(alternativeSolution(matrix, 15), true, |
175 | | - "alternative contains 15"); |
176 | | - runner.summary(); |
177 | | -} |
178 | | - |
179 | | -int main() { |
180 | | - test(); |
181 | | - return 0; |
| 114 | + t.summary(); |
| 115 | + return (t.failed == 0) ? 0 : 1; |
182 | 116 | } |
0 commit comments