Idea :

for matrix[i,j] -> It's belong to a level (determent how close to boundary , i to 0 or rows, j to 0 or cols).

so min of ( i-0 , j - 0 , rows-1-i , cols-1-j ) will be it's level .

For level k, there are total number of items in level k will be (rows- 2 * k) * 2 + (cols - 2 * k) * 2. and it's start point will be rows*cols - (rows- 2 * k)*(cols-2*k).

In each level,

if item is in top and right, then its index in result will be

index = (start point of this level) + (distance between matrix[i,j] and matrix[level,level]

= rows*cols - (rows-level*2) * (cols-level*2)+i-level+j-level

if item is in bottom and left, then its index in result will be

index = (start point of next level ) - (distance between matrix[i,j] and matrix[level,level])

= rows*cols - (rows-(min+1)*2) * (cols-(min+1)*2) - (i-min+j-min)

```
public class Solution {
public IList<int> SpiralOrder(int[,] matrix) {
int rows = matrix.GetLength(0);
int cols = matrix.GetLength(1);
var result = new int[rows*cols];
for(int i = 0;i<rows;i++){
for(int j = 0;j<cols;j++){
int min = Math.Min(Math.Min(i,rows-1-i),Math.Min(j,cols-j-1));
int startPoint = rows*cols - (rows-min*2) * (cols-min*2);
if(i == min || cols-j-1 == min){
result[startPoint+i-min+j-min] = matrix[i,j];
}else{
result[rows*cols - (rows-(min+1)*2) * (cols-(min+1)*2) - (i-min+j-min)] = matrix[i,j];
}
}
}
return result.ToList();
}
}
```