Problem
Source: Codewars
Given an n x n array, return the array elements arranged from outermost elements to the middle element, traveling clockwise.
array = [[1,2,3],
[4,5,6],
[7,8,9]]
snail(array) #=> [1,2,3,6,9,8,7,4,5]
For better understanding, please follow the numbers of the next array consecutively:
array = [[1,2,3],
[8,9,4],
[7,6,5]]
snail(array) #=> [1,2,3,4,5,6,7,8,9]
This image will illustrate things more clearly:
NOTE: The idea is not sort the elements from the lowest value to the highest; the idea is to traverse the 2-d array in a clockwise snailshell pattern.
NOTE 2: The 0x0 (empty matrix) is represented as en empty array inside an array [[]].
Solution
This problem is simpler than its 4-kyuu label. To traverse in a snailshell pattern, I will traverse the 0th row, n-1th collumn, n-1th row, 1st collumn,.. respectively.
First of all is to declare these variables:
std::vector<int> res;
int row_start = 0; // Top-most row
int col_start = 0; // Left-most collumn
int row_end = snail_map.size(); // Bottom-most row
int col_end = row_end; // Right-most collumn
Start from the topmost row, increase the collumn index to traverse through it:
for (int i = col_start; i < col_end; i++)
res.push_back(snail_map[row_start][i]);
The same with the rightmost collumn, increase the row index to traverse. It should be noted that the top right element (snail_map[row_start][col_end-1]
) has to be skipped since it has been read before.
for (int i = ++row_start; i < row_end; i++)
res.push_back(snail_map[i][col_end-1]);
Due to snailshell pattern, traversing the bottom-most row need to be done in backwards: decrease the collumn index instead of increasing. And because the bottom right element (snail_map[row_end-1][col_end-1]
) has been read, the right most collumn will be skipped.
for (i = (--col_end)-1; i >= col_start; --i)
res.push_back(snail_map[row_end-1][i]);
Similarly, decrease the row index to traverse the left most collumn in backwards.
for (int i = (--row_end)-1; i >= row_start; --i)
res.push_back(snail_map[i][col_start]);
These operations will be looped until the given map is traversed, which means, row_start
and row_end
, or col_start
and col_end
, passed each others (_start
$\geq$ _end
). Besides, an empty map case should be considered.
if(snail_map.empty() || snail_map[0].empty())
return {};
With all that, the solution for this kata is completed.
#include<vector>
std::vector<int> snail(const std::vector<std::vector<int>> &snail_map){
if(snail_map.empty() || snail_map[0].empty())
return {};
std::vector<int> res;
int row_start = 0; // Top-most row
int col_start = 0; // Left-most collumn
int row_end = snail_map.size(); // Bottom-most row
int col_end = row_end; // Right-most collumn
while (row_start <= row_end && col_start <= col_end){
for (int i = col_start; i <= col_end; i++)
res.push_back(snail_map[row_start][i]);
for (int i = ++row_start; i <= row_end; i++)
res.push_back(snail_map[i][col_end]);
for (int i = --col_end; i >= col_start; i--)
res.push_back(snail_map[row_end][i]);
for (int i = row_end; i >= row_start; i--)
res.push_back(snail_map[i][col_start]);
col_start++;
}
return res;
};
Also a solution
If you are more familiar with while
loop, here is how the solution could be rewritten:
int row = 0, col = 0;
while (row_start <= row_end && col_start <= col_end) {
while (col < col_end) res.push_back(snail_map[row][col++]); row_start++;
while (row < row_end) res.push_back(snail_map[row++][col]); col_end--;
while (col > col_start) res.push_back(snail_map[row][col--]); row_end--;
while (row > row_start) res.push_back(snail_map[row--][col]); col_start++;
}
res.push_back(snail_map[row][col]); // Adding the last element
Two variables row
and col
are used to mark the current row and collumn, the two variables only change from 0
to n-2
. so that the next while
could make use of current values of row
and col
without traverse through the same element twice, in other words, instead of skipping the read element, I will leave the last element of the current row/col. And because of this, it is a need to add the last element of the map after the while
loop is done.
Thank you for reading.