Skip to content

Commit 17328d4

Browse files
Merge pull request #605 from InfinityxR9/algorithms_#595
Added 2D Matrix Searching Problems and Spiral Traversal Algorithm in C++ #595
2 parents 496f05c + 87ef5a2 commit 17328d4

File tree

4 files changed

+840
-16
lines changed

4 files changed

+840
-16
lines changed

.vscode/c_cpp_properties.json

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,29 @@
11
{
2-
"configurations": [
3-
{
4-
"name": "macos-gcc-arm64",
5-
"includePath": [
6-
"${workspaceFolder}/**"
7-
],
8-
"compilerPath": "/Users/shubham/bin/gcc",
9-
"cStandard": "${default}",
10-
"cppStandard": "${default}",
11-
"intelliSenseMode": "macos-gcc-arm64",
12-
"compilerArgs": [
13-
""
14-
]
15-
}
16-
],
17-
"version": 4
2+
"configurations": [
3+
{
4+
"name": "macos-gcc-arm64",
5+
"includePath": [
6+
"${workspaceFolder}/**"
7+
],
8+
"compilerPath": "/Users/shubham/bin/gcc",
9+
"cStandard": "${default}",
10+
"cppStandard": "${default}",
11+
"intelliSenseMode": "macos-gcc-arm64",
12+
"compilerArgs": [
13+
""
14+
]
15+
},
16+
{
17+
"name": "Linux",
18+
"includePath": [
19+
"${workspaceFolder}/**"
20+
],
21+
"defines": [],
22+
"compilerPath": "/usr/bin/gcc",
23+
"cStandard": "c17",
24+
"cppStandard": "gnu++17",
25+
"intelliSenseMode": "linux-gcc-x64"
26+
}
27+
],
28+
"version": 4
1829
}
Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
/*************************************************************************
2+
* @author: Aryan Sisodiya (@InfinityxR9) (https://github.com/InfinityxR9)
3+
* @category: Problem
4+
* @date: 9 October, 2025
5+
* @name: Search in a 2D Matrix (Implemented as 2D STL Vector) - I
6+
* DIFFICULTY: Medium
7+
*
8+
* LeetCode Reference: https://leetcode.com/problems/search-a-2d-matrix/
9+
* Constrains:
10+
* * m == matrix.length
11+
* * n == matrix[i].length
12+
* * 1 <= m, n <= 100
13+
* * -104 <= matrix[i][j], target <= 104
14+
*
15+
* @details
16+
* You are given a m x n integer matrix with the following two properties:
17+
* * Each row is sorted in non-decreasing order.
18+
* * The first integer of each row is greater than the last integer of the previous row.
19+
*
20+
* Given an integer target, return true if target is in matrix or false otherwise.
21+
*
22+
* You must write a solution in O(log(m * n)) time complexity.
23+
*
24+
* @example
25+
* Input: matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3
26+
* Output: true
27+
*
28+
* Input: matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 13
29+
* Output: false
30+
*
31+
* Approach: Using Binary Search Twice
32+
* * (1) We use binary search first to find out the target lies in which row
33+
* (2) We use binary search second on that row to find out whether target lies in matrix or not.
34+
*
35+
* * The matrix is sorted in a zig-zag fashion.
36+
* * Hence, the Binary Search approach is very well applicable.
37+
*
38+
*
39+
* Time Complexity: O(log (m * n))
40+
* Space Complexity: O(1)
41+
*
42+
*
43+
*/
44+
45+
// Necessary Header Files import
46+
#include <iostream>
47+
#include <vector>
48+
#include <random>
49+
#include <algorithm>
50+
51+
using namespace std;
52+
53+
/**
54+
* Core Algorithm using Binary Search twice to find `target`
55+
* @param matrix The 2D Matrix (with specified properties), in which the `target` is to be searched
56+
* @param target The value to be searched in the `matrix`
57+
* @return Whether the `target` is present in the `matrix` or not
58+
*/
59+
bool searchMatrix(vector<vector<int>> &matrix, int target)
60+
{
61+
// Variables Assignment to find the row
62+
int sRow = 0, eRow = matrix.size() - 1, sMid;
63+
64+
while (sRow <= eRow)
65+
{
66+
sMid = sRow + (eRow - sRow) / 2;
67+
68+
if (matrix[sMid][0] <= target &&
69+
matrix[sMid][matrix[sMid].size() - 1] >= target)
70+
break;
71+
else if (matrix[sMid][0] < target &&
72+
matrix[sMid][matrix[sMid].size() - 1] < target)
73+
sRow = sMid + 1; // Search in right half
74+
else
75+
eRow = sMid - 1; // Search in left half
76+
}
77+
78+
// Variables assignment for Binary Search in so found row
79+
int low = 0, high = matrix[sMid].size() - 1, mid;
80+
81+
while (low <= high)
82+
{
83+
mid = low + (high - low) / 2;
84+
85+
if (matrix[sMid][mid] == target)
86+
return true; // target found!
87+
else if (matrix[sMid][mid] < target)
88+
low = mid + 1;
89+
else
90+
high = mid - 1;
91+
}
92+
93+
return false;
94+
}
95+
96+
/**
97+
* Running Single Test Case
98+
* @param input The 2D Matrix with specified property
99+
* @param target The target value to be searched in the 2D Matrix
100+
* @param expected The expected output
101+
* @param testName Test Case brief Description
102+
*/
103+
void run_test(vector<vector<int>> input, const int target, const bool expected, const string testName)
104+
{
105+
bool ans = searchMatrix(input, target);
106+
if (ans == expected)
107+
{
108+
cout << "[PASS] " << testName << endl;
109+
}
110+
else
111+
{
112+
cout << "[FAIL] " << testName << endl;
113+
cout << " Expected: " << expected;
114+
cout << "\n Got: " << ans;
115+
cout << "\n\n";
116+
}
117+
}
118+
119+
/**
120+
* Utility function to build a strictly-increasing flattened matrix with `rows` x `cols`.
121+
* @param rows Number of rows
122+
* @param cols Number of columns
123+
* @param start The start value `default = 1`
124+
* @param step The start value `default = 1`
125+
* @return The `matrix` so builded
126+
*/
127+
vector<vector<int>> build_increasing_matrix(int rows, int cols, int start = 1, int step = 1)
128+
{
129+
vector<vector<int>> mat(rows, vector<int>());
130+
int val = start;
131+
for (int r = 0; r < rows; ++r)
132+
{
133+
for (int c = 0; c < cols; ++c)
134+
{
135+
mat[r].push_back(val);
136+
val += step;
137+
}
138+
}
139+
return mat;
140+
}
141+
142+
/**
143+
* Utility function to Run all the test cases
144+
*/
145+
void test_cases()
146+
{
147+
// 1-2: Given examples
148+
run_test({{1, 3, 5, 7}, {10, 11, 16, 20}, {23, 30, 34, 60}}, 3, true, "Example Case 1: Found (middle row)");
149+
run_test({{1, 3, 5, 7}, {10, 11, 16, 20}, {23, 30, 34, 60}}, 13, false, "Example Case 2: Not present");
150+
151+
// 3-4: Single element
152+
run_test({{5}}, 5, true, "Single element present");
153+
run_test({{5}}, -5, false, "Single element absent");
154+
155+
// 5-8: Single row
156+
run_test({{1, 3, 5, 7, 9}}, 7, true, "Single row: present (middle)");
157+
run_test({{1, 3, 5, 7, 9}}, 2, false, "Single row: absent (between)");
158+
run_test({{1, 3, 5, 7, 9}}, 1, true, "Single row: first element");
159+
run_test({{1, 3, 5, 7, 9}}, 9, true, "Single row: last element");
160+
161+
// 9-10: Single column
162+
run_test({{1}, {3}, {5}, {7}, {9}}, 5, true, "Single column: middle present");
163+
run_test({{1}, {3}, {5}, {7}, {9}}, 4, false, "Single column: absent between rows");
164+
165+
// 11-13: Multi-row: first, last, between
166+
run_test({{1, 2, 3}, {10, 11, 12}, {20, 21, 22}}, 1, true, "Multi-row: first element");
167+
run_test({{1, 2, 3}, {10, 11, 12}, {20, 21, 22}}, 22, true, "Multi-row: last element");
168+
run_test({{1, 2, 3}, {10, 11, 12}, {20, 21, 22}}, 15, false, "Multi-row: value between rows");
169+
170+
// 14-15: Large gaps
171+
run_test({{1, 2, 3}, {100, 200, 300}, {1000, 2000, 3000}}, 200, true, "Large gap: present");
172+
run_test({{1, 2, 3}, {100, 200, 300}, {1000, 2000, 3000}}, 250, false, "Large gap: absent");
173+
174+
// 16-17: Negatives
175+
run_test({{-10, -5, -2}, {0, 2, 4}, {10, 20, 30}}, -5, true, "Negative number present");
176+
run_test({{-10, -5, -2}, {0, 2, 4}, {10, 20, 30}}, -6, false, "Negative number absent");
177+
178+
// 18-19: Mix negatives and positives
179+
run_test({{-100, -50, -10}, {0, 1, 2}, {10, 20, 30}}, 0, true, "Zero present (row boundary)");
180+
run_test({{-100, -50, -10}, {0, 1, 2}, {10, 20, 30}}, 3, false, "Positive absent across rows");
181+
182+
// 20-21: Outside range
183+
run_test({{5, 10, 15}, {20, 25, 30}}, 1, false, "Target smaller than min");
184+
run_test({{5, 10, 15}, {20, 25, 30}}, 35, false, "Target larger than max");
185+
186+
// 22-23: 2x2
187+
run_test({{1, 2}, {3, 4}}, 3, true, "2x2 present");
188+
run_test({{1, 2}, {3, 4}}, 5, false, "2x2 absent");
189+
190+
// 24-25: 3x1 column
191+
run_test({{2}, {4}, {6}}, 4, true, "3x1 column present");
192+
run_test({{2}, {4}, {6}}, 5, false, "3x1 column absent");
193+
194+
// 26-27: Random small valid matrices
195+
run_test({{1, 4, 7}, {10, 14, 18}, {25, 30, 35}}, 30, true, "Random small: present");
196+
run_test({{1, 4, 7}, {10, 14, 18}, {25, 30, 35}}, 26, false, "Random small: absent");
197+
198+
// 28-29: 4x4
199+
run_test({{1, 2, 3, 4}, {10, 11, 12, 13}, {20, 21, 22, 23}, {30, 31, 32, 33}}, 22, true, "4x4 present");
200+
run_test({{1, 2, 3, 4}, {10, 11, 12, 13}, {20, 21, 22, 23}, {30, 31, 32, 33}}, 19, false, "4x4 absent (gap)");
201+
202+
// 30-32: Boundary extremes (constraints: -10^4 .. 10^4)
203+
run_test({{-10000, -9999, -9998}, {0, 1, 2}, {9998, 9999, 10000}}, -10000, true, "Boundary min present");
204+
run_test({{-10000, -9999, -9998}, {0, 1, 2}, {9998, 9999, 10000}}, 10000, true, "Boundary max present");
205+
run_test({{-10000, -9999, -9998}, {0, 1, 2}, {9998, 9999, 10000}}, 5000, false, "Boundary mid absent");
206+
207+
// 33-34: Larger random-like
208+
run_test({{1, 3, 5, 7, 9, 11}, {20, 22, 24, 26, 28, 30}, {40, 42, 44, 46, 48, 50}}, 28, true, "Larger random: present");
209+
run_test({{1, 3, 5, 7, 9, 11}, {20, 22, 24, 26, 28, 30}, {40, 42, 44, 46, 48, 50}}, 29, false, "Larger random: absent");
210+
211+
// 35-36: Sequential 1..9
212+
run_test({{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, 8, true, "Sequential present");
213+
run_test({{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, 10, false, "Sequential absent");
214+
215+
// 37-38: Rectangular 2x5
216+
run_test({{1, 2, 3, 4, 5}, {10, 11, 12, 13, 14}}, 12, true, "Rectangular 2x5 present");
217+
run_test({{1, 2, 3, 4, 5}, {10, 11, 12, 13, 14}}, 9, false, "Rectangular 2x5 absent");
218+
219+
// 39-40: Row transitions
220+
run_test({{1, 2, 3}, {10, 11, 12}, {20, 21, 22}}, 10, true, "Row transition: first element of middle row");
221+
run_test({{1, 2, 3}, {10, 11, 12}, {20, 21, 22}}, 12, true, "Row transition: last element of middle row");
222+
223+
// 41-42: Mixed intervals
224+
run_test({{2, 4, 6, 8}, {15, 20, 25, 30}, {100, 200, 300, 400}}, 300, true, "Mixed intervals: present");
225+
run_test({{2, 4, 6, 8}, {15, 20, 25, 30}, {100, 200, 300, 400}}, 99, false, "Mixed intervals: absent");
226+
227+
// 43-44: Repeated values inside rows (allowed) but strict across rows
228+
run_test({{1, 1, 1, 2}, {3, 3, 3, 4}}, 1, true, "Repeateds in row: find repeat value");
229+
run_test({{1, 1, 1, 2}, {3, 3, 3, 4}}, 3, true, "Repeateds in next row: find repeat value");
230+
231+
// 45: All-equal single row
232+
run_test({{2, 2, 2, 2}}, 2, true, "Single row all-equal: present");
233+
234+
// 46: Varying row lengths
235+
run_test({{1, 2}, {3, 4, 5}, {6}}, 5, true, "Varying row lengths: present");
236+
237+
// 47: Absent just after first row
238+
run_test({{1, 2, 3}, {10, 11, 12}}, 4, false, "Absent just after first row (gap)");
239+
240+
// 48: Negative to zero transition with duplicates
241+
run_test({{-3, -2, -1}, {0, 0, 1}}, 0, true, "Negative->Zero with duplicates: present");
242+
243+
// 49: Long single row (n = 100) - generated
244+
{
245+
vector<int> longRow;
246+
longRow.reserve(100);
247+
for (int i = 0; i < 100; ++i)
248+
longRow.push_back(i * 2 + 1); // odd numbers 1..199
249+
run_test({longRow}, 199, true, "Long single row (n=100): last element present");
250+
run_test({longRow}, 100, false, "Long single row (n=100): absent even number");
251+
}
252+
253+
// 50-52: Programmatic, deterministic random-ish matrices (fixed seed)
254+
{
255+
mt19937 rng(42);
256+
for (int t = 0; t < 3; ++t)
257+
{
258+
int rows = 1 + (rng() % 6); // 1..6 rows
259+
int cols = 1 + (rng() % 8); // 1..8 cols
260+
int start = -50 + (rng() % 101); // -50..50
261+
int step = 1 + (rng() % 5); // 1..5
262+
auto M = build_increasing_matrix(rows, cols, start, step);
263+
264+
// pick a random cell to be the target (should be present)
265+
int rr = rng() % rows;
266+
int cc = rng() % cols;
267+
int target_present = M[rr][cc];
268+
run_test(M, target_present, true, "GenMatrix present (deterministic seed)");
269+
270+
// pick a value guaranteed absent: take last element and add 1
271+
int last = M[rows - 1][cols - 1];
272+
int target_absent = last + 1;
273+
run_test(M, target_absent, false, "GenMatrix absent (just above last)");
274+
}
275+
}
276+
}
277+
278+
// Main function
279+
int main()
280+
{
281+
// Running the test cases
282+
test_cases();
283+
284+
return 0;
285+
}

0 commit comments

Comments
 (0)