Skip to content

Commit 53380da

Browse files
authored
Refactor magic square verification logic and comments
Refactor magic square verification with improved comments and structure. Simplify checks for rows, columns, and diagonals in both simple and optimal solutions.
1 parent fb7a87a commit 53380da

1 file changed

Lines changed: 129 additions & 166 deletions

File tree

src/5_Matrices/magic_square.cpp

Lines changed: 129 additions & 166 deletions
Original file line numberDiff line numberDiff line change
@@ -1,226 +1,189 @@
11
/*
22
* Task: Verify whether a square matrix is a magic square.
33
*
4-
* MAGIC SQUARE VERIFICATION
4+
* A magic square is an n x n matrix where:
5+
* - Every row sum is the same
6+
* - Every column sum is the same
7+
* - Main diagonal sum is the same
8+
* - Anti-diagonal sum is the same
59
*
6-
* Check if a given square matrix is a magic square. A magic square is defined
7-
* as an n x n matrix in which the sums of each row, each column, the main
8-
* diagonal, and the anti-diagonal are all equal.
10+
* Example (3x3):
11+
* [ 8, 1, 6 ]
12+
* [ 3, 5, 7 ]
13+
* [ 4, 9, 2 ]
14+
* All sums = 15 -> true
915
*
10-
* ASCII Illustration:
11-
*
12-
* [ 8, 1, 6 ]
13-
* [ 3, 5, 7 ]
14-
* [ 4, 9, 2 ]
15-
*
16-
* All rows, columns, and diagonals sum to 15.
17-
*
18-
* Example:
19-
* Input:
20-
* magicSquare = [ [8, 1, 6],
21-
* [3, 5, 7],
22-
* [4, 9, 2] ]
23-
*
24-
* Output:
25-
* true
26-
*
27-
* Explanation:
28-
* Each row, column, and diagonal sums to 15, hence the matrix is a magic
29-
* square.
3016
*/
3117

3218
#include <iostream>
33-
#include <numeric>
19+
#include <stdexcept>
3420
#include <string>
3521
#include <vector>
3622

37-
// ----------------------- Simple (Brute-force) Solution -----------------------
38-
bool isMagicSquareSimple(const std::vector<std::vector<int>> &matrix) {
39-
int n = matrix.size();
40-
if (n == 0)
41-
return false;
42-
// Check if matrix is square.
43-
for (const auto &row : matrix) {
44-
if (row.size() != static_cast<size_t>(n))
45-
return false;
23+
// ----------------------- 1) Simple (Brute-force) Solution --------------------
24+
//
25+
// Idea:
26+
// - Compute target sum from first row.
27+
// - Check all row sums, all column sums, then both diagonals.
28+
//
29+
// Time Complexity:
30+
// - Row checks: O(n^2)
31+
// - Column checks: O(n^2)
32+
// - Diagonals: O(n)
33+
// => Total: O(n^2)
34+
//
35+
// Space Complexity:
36+
// - O(1) extra space.
37+
//
38+
bool isMagicSquareSimple(const std::vector<std::vector<int>>& matrix) {
39+
const int n = static_cast<int>(matrix.size());
40+
if (n == 0) return false;
41+
42+
// Validate square matrix: O(n)
43+
for (const auto& row : matrix) {
44+
if (static_cast<int>(row.size()) != n) return false;
4645
}
4746

48-
// Compute the target sum from the first row.
47+
// Target sum = first row: O(n)
4948
int target = 0;
50-
for (int num : matrix[0])
51-
target += num;
52-
53-
// Check row sums.
54-
for (const auto &row : matrix) {
55-
int sum = 0;
56-
for (int num : row)
57-
sum += num;
58-
if (sum != target)
59-
return false;
49+
for (int v : matrix[0]) target += v;
50+
51+
// Check rows: O(n^2)
52+
for (int i = 0; i < n; ++i) {
53+
int rowSum = 0;
54+
for (int j = 0; j < n; ++j) rowSum += matrix[i][j];
55+
if (rowSum != target) return false;
6056
}
6157

62-
// Check column sums.
58+
// Check columns: O(n^2)
6359
for (int j = 0; j < n; ++j) {
64-
int sum = 0;
65-
for (int i = 0; i < n; ++i)
66-
sum += matrix[i][j];
67-
if (sum != target)
68-
return false;
60+
int colSum = 0;
61+
for (int i = 0; i < n; ++i) colSum += matrix[i][j];
62+
if (colSum != target) return false;
6963
}
7064

71-
// Check main diagonal.
65+
// Check main diagonal: O(n)
7266
int diag1 = 0;
73-
for (int i = 0; i < n; ++i)
74-
diag1 += matrix[i][i];
75-
if (diag1 != target)
76-
return false;
67+
for (int i = 0; i < n; ++i) diag1 += matrix[i][i];
68+
if (diag1 != target) return false;
7769

78-
// Check anti-diagonal.
70+
// Check anti-diagonal: O(n)
7971
int diag2 = 0;
80-
for (int i = 0; i < n; ++i)
81-
diag2 += matrix[i][n - 1 - i];
82-
if (diag2 != target)
83-
return false;
72+
for (int i = 0; i < n; ++i) diag2 += matrix[i][n - 1 - i];
73+
if (diag2 != target) return false;
8474

8575
return true;
8676
}
8777

88-
// ----------------------- Optimal (Single-pass) Solution
89-
// -----------------------
90-
bool isMagicSquareOptimal(const std::vector<std::vector<int>> &matrix) {
91-
int n = matrix.size();
92-
if (n == 0)
93-
return false;
94-
for (const auto &row : matrix)
95-
if (row.size() != static_cast<size_t>(n))
96-
return false;
97-
98-
// Calculate target sum from the first row.
78+
// ----------------------- 2) Optimal (Single-pass) Solution -------------------
79+
//
80+
// Idea:
81+
// - Compute target from first row.
82+
// - In ONE traversal:
83+
// * compute each row sum and compare immediately
84+
// * accumulate column sums
85+
// * accumulate both diagonals
86+
// - After traversal, verify diagonals + column sums.
87+
//
88+
// Time Complexity:
89+
// - Single traversal of all cells: O(n^2)
90+
// - Final column verification: O(n)
91+
// => Total: O(n^2)
92+
//
93+
// Space Complexity:
94+
// - O(n) for column sums.
95+
//
96+
bool isMagicSquareOptimal(const std::vector<std::vector<int>>& matrix) {
97+
const int n = static_cast<int>(matrix.size());
98+
if (n == 0) return false;
99+
100+
// Validate square matrix: O(n)
101+
for (const auto& row : matrix) {
102+
if (static_cast<int>(row.size()) != n) return false;
103+
}
104+
105+
// Target sum = first row: O(n)
99106
int target = 0;
100-
for (int j = 0; j < n; ++j)
101-
target += matrix[0][j];
107+
for (int v : matrix[0]) target += v;
102108

109+
std::vector<int> colSum(n, 0); // O(n) space
103110
int diag1 = 0, diag2 = 0;
104-
// Initialize column sums.
105-
std::vector<int> colSum(n, 0);
106111

112+
// Single pass over matrix: O(n^2)
107113
for (int i = 0; i < n; ++i) {
108114
int rowSum = 0;
109115
for (int j = 0; j < n; ++j) {
110-
rowSum += matrix[i][j];
111-
colSum[j] += matrix[i][j];
116+
const int val = matrix[i][j];
117+
rowSum += val; // row sum
118+
colSum[j] += val; // column sums
112119
}
113-
if (rowSum != target)
114-
return false;
115-
diag1 += matrix[i][i];
116-
diag2 += matrix[i][n - 1 - i];
117-
}
120+
if (rowSum != target) return false; // early exit
118121

119-
if (diag1 != target || diag2 != target)
120-
return false;
121-
122-
for (int sum : colSum)
123-
if (sum != target)
124-
return false;
125-
126-
return true;
127-
}
128-
129-
// ----------------------- Alternative (STL-based) Solution
130-
// -----------------------
131-
bool isMagicSquareAlternative(const std::vector<std::vector<int>> &matrix) {
132-
int n = matrix.size();
133-
if (n == 0)
134-
return false;
135-
for (const auto &row : matrix)
136-
if (row.size() != static_cast<size_t>(n))
137-
return false;
138-
139-
// Compute target sum using std::accumulate on first row.
140-
int target = std::accumulate(matrix[0].begin(), matrix[0].end(), 0);
141-
142-
// Check rows using std::accumulate.
143-
for (const auto &row : matrix) {
144-
if (std::accumulate(row.begin(), row.end(), 0) != target)
145-
return false;
122+
diag1 += matrix[i][i]; // main diagonal
123+
diag2 += matrix[i][n - 1 - i]; // anti-diagonal
146124
}
147125

148-
// Check columns.
126+
// Diagonals: O(1) check
127+
if (diag1 != target || diag2 != target) return false;
128+
129+
// Columns: O(n)
149130
for (int j = 0; j < n; ++j) {
150-
int colSum = 0;
151-
for (int i = 0; i < n; ++i)
152-
colSum += matrix[i][j];
153-
if (colSum != target)
154-
return false;
131+
if (colSum[j] != target) return false;
155132
}
156133

157-
// Check main diagonal.
158-
int diag1 = 0;
159-
for (int i = 0; i < n; ++i)
160-
diag1 += matrix[i][i];
161-
if (diag1 != target)
162-
return false;
163-
164-
// Check anti-diagonal.
165-
int diag2 = 0;
166-
for (int i = 0; i < n; ++i)
167-
diag2 += matrix[i][n - 1 - i];
168-
if (diag2 != target)
169-
return false;
170-
171134
return true;
172135
}
173136

174-
namespace {
137+
// ------------------------------ Tests (2 examples) ---------------------------
138+
//
139+
// Time Complexity of tests is irrelevant; tiny fixed-size inputs.
140+
//
175141
struct TestRunner {
176142
int total = 0;
177143
int failed = 0;
178144

179-
void expectEqual(bool got, bool expected, const std::string &label) {
145+
void expectEqual(bool got, bool expected, const std::string& label) {
180146
++total;
181147
if (got == expected) {
182148
std::cout << "[PASS] " << label << "\n";
183-
return;
149+
} else {
150+
++failed;
151+
std::cout << "[FAIL] " << label << " expected=" << std::boolalpha
152+
<< expected << " got=" << got << "\n";
184153
}
185-
++failed;
186-
std::cout << "[FAIL] " << label << " expected=" << std::boolalpha
187-
<< expected << " got=" << got << "\n";
188154
}
189155

190156
void summary() const {
191-
std::cout << "Tests: " << total - failed << " passed, " << failed
157+
std::cout << "Tests: " << (total - failed) << " passed, " << failed
192158
<< " failed, " << total << " total\n";
193159
}
194160
};
195-
} // namespace
196-
197-
// ----------------------- Test cases for correctness -----------------------
198-
void test() {
199-
std::vector<std::vector<int>> magicSquare = {{8, 1, 6}, {3, 5, 7}, {4, 9, 2}};
200-
201-
std::vector<std::vector<int>> nonMagicSquare = {
202-
{5, 3, 4}, {1, 5, 8}, {6, 4, 2}};
203-
TestRunner runner;
204-
205-
// Test Simple Solution
206-
runner.expectEqual(isMagicSquareSimple(magicSquare), true, "simple magic");
207-
runner.expectEqual(isMagicSquareSimple(nonMagicSquare), false,
208-
"simple non-magic");
209-
210-
// Test Optimal Solution
211-
runner.expectEqual(isMagicSquareOptimal(magicSquare), true, "optimal magic");
212-
runner.expectEqual(isMagicSquareOptimal(nonMagicSquare), false,
213-
"optimal non-magic");
214-
215-
// Test Alternative Solution
216-
runner.expectEqual(isMagicSquareAlternative(magicSquare), true,
217-
"alternative magic");
218-
runner.expectEqual(isMagicSquareAlternative(nonMagicSquare), false,
219-
"alternative non-magic");
220-
runner.summary();
221-
}
222161

223162
int main() {
224-
test();
225-
return 0;
163+
// Example 1: Magic square -> true
164+
std::vector<std::vector<int>> magic = {
165+
{8, 1, 6},
166+
{3, 5, 7},
167+
{4, 9, 2},
168+
};
169+
170+
// Example 2: Not a magic square -> false
171+
std::vector<std::vector<int>> notMagic = {
172+
{5, 3, 4},
173+
{1, 5, 8},
174+
{6, 4, 2},
175+
};
176+
177+
TestRunner t;
178+
179+
// Simple
180+
t.expectEqual(isMagicSquareSimple(magic), true, "simple: magic");
181+
t.expectEqual(isMagicSquareSimple(notMagic), false, "simple: not magic");
182+
183+
// Optimal
184+
t.expectEqual(isMagicSquareOptimal(magic), true, "optimal: magic");
185+
t.expectEqual(isMagicSquareOptimal(notMagic), false, "optimal: not magic");
186+
187+
t.summary();
188+
return (t.failed == 0) ? 0 : 1;
226189
}

0 commit comments

Comments
 (0)