Reputation: 1052
We are given a square matrix which is filled with numbers from [1,n*n] in a row major form. We have to find the kth element when we traverse it in a spiral order. The only solution I could think was to to do a spiral traversal and maintain a counter for number of elements traversed. When counter value becomes k, we print the number at that instance.
Can this be solved in less than O(n*n)? If yes, then how to solve the same problem when matrix elements with random elements?
Upvotes: 2
Views: 1902
Reputation: 5357
Here is O(1)
solution. I've tried to leave explanation for each step in the comments.
// takes q as zero based number in spiral traversal on square array n*n
// and returns zero based x, y coordinates in rectangular array with center
// at left top corner
public void SpiralToRect(int n, int q, out int x, out int y)
{
// partial sum for rings count is 4 * k * (n - k)
// ring counts go like this: 4 * (n - 1), 4 * (n - 3), ..., 4 * (n - 2k + 1)
// partial sum is 4 * k * n - 4 * k * k
// consider equation partial sum on k rings = q
int k = (int)Math.Floor((n - Math.Sqrt(n * n - q)) / 2);
// offset of element inside the ring is q - partial sum for k
int ringOffset = q - 4 * k * (n - k);
// it's easy to see how len of segments for k-th ring are calculated
int[] l = new[]
{
n - 2 * k, // top
n - 2 * k - 1, // right
n - 2 * k - 1, // bottom
n - 2 * k - 2, // left
};
// notice how kth ring starts at (k, k)
if (ringOffset < l[0]) // top row
{
x = k + ringOffset;
y = k;
}
else if (ringOffset < l[0] + l[1]) // right col
{
x = k + l[0] - 1;
y = k + ringOffset - l[0] + 1;
}
else if (ringOffset < l[0] + l[1] + l[2]) // bottom row
{
x = k + 2 * l[0] + l[1] - ringOffset - 2;
y = k + l[1];
}
else // left column
{
x = k;
y = k + l[0] + 2 * l[1] + l[2] - ringOffset - 1;
}
}
For the sample array below it returns numbers 1, 2, ..., 35, 36
.
void Main()
{
int[,] spiral = new int[,]
{
{ 01, 02, 03, 04, 05, 06, },
{ 20, 21, 22, 23, 24, 07, },
{ 19, 32, 33, 34, 25, 08, },
{ 18, 31, 36, 35, 26, 09, },
{ 17, 30, 29, 28, 27, 10, },
{ 16, 15, 14, 13, 12, 11, },
};
for (int q = 0; q < 36; q++)
{
int x, y;
SpiralToRect(6, q, out x, out y);
spiral[y, x].Dump();
}
}
Upvotes: 0
Reputation: 578
The first circle have 4(n - 1)
nodes,
the second circle have 4(n - 2)
nodes,
...
the last circle have 1
nodes.
step 1: you locate which circle the element you find is. O(n)
step 2: use traversed method to determine this element. O(4n)
At last, O(n)
Upvotes: 2