解法:
这道题并没有用到有多高深的算法,但是需要保证好循环不变量原则,即每次循环的区间能改变,如果每次循环区间都改变,那么我们就需要做无数个判断,这显然是不符合题意的。
博主采取了“左闭右开”的区间取法。我们将数据按照螺旋存入二维数组,需要转多少圈呢?
每存储一圈时,在下一圈开始存储时,我们可以看到任意一条边上都消失了两个顶点,因此共需要存储n/2圈。
每一次存储时的开始位置是一个变化的量,第一次从第0列开始,第二次从1列开始......由此我们可以见得在存储一圈后需要给start(开始位置)++
同样因为采取了左闭右开的区间取法,结束的位置同样是动态的。
按照题中给出的循环顺序,分别写入四个循环进行条件判断最终就可以得到答案。
注意:如果所给的n是奇数的话,中间会多出一个数,这个数的位置是start结束位置++
注意:arr[i][j]=cont++
等于arr[i][j]=cont;
cont++;
class Solution {
public int[][] generateMatrix(int n) {
int cont=1;
int start=0;//起始位置
int loop=0;//终止时,停止变量
int i,j;//i是行,j是列
int[][] arr=new int[n][n];//创建数组将元素存入
while(loop++<n/2){//每次转一圈,一条边都会少两个数,少了多少个两个数就是转多少圈
//上面的边,从左到右遍历
for(j=start;j<n-loop;j++){
arr[start][j]=cont++;
}
//右边的边,从上到下遍历
for(i=start;i<n-loop;i++){
arr[i][j]=cont++;
}
//下边的边,从右到左遍历
for(;j>=loop;j--){
arr[i][j]=cont++;
}
for(;i>=loop;i--){
arr[i][j]=cont++;
}
start++;
}
if(n%2==1){
arr[start][start]=cont;//如果是奇数,中间最后的元素是遍历结束的start
}
return arr;
}
}
解法:和上道题类似,这种题是真的很恶心,虽然没什么套路就记着循环不变量,但是只要一变化就要处理一些细节问题。
还是和上面那道题一样采取左闭右开的区间取法,遍历完成后我们发现,循环的圈数是较短边2的倍数,同时如果较短边是奇数,则会剩下一条线,这个线需要我们手动去加入,起始位置是循环结束的start,终止位置是长边长度剪去start。
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
ArrayList<Integer> list = new ArrayList<>();
int n = matrix.length;//有n列
int m = matrix[0].length;//有m行
int start = 0;
int end = 1;
int loop = 0;
int i = 0, j = 0;//i 行 j列
while (loop < n / 2 && loop < m / 2) {
//上边
for (j = start; j < m - end; j++) {
list.add(matrix[start][j]);
}
//右边
for (i = start; i < n - end; i++) {
list.add(matrix[i][j]);
}
//下面
for (; j >= end; j--) {
list.add(matrix[i][j]);
}
//左边
for (; i >= end; i--) {
list.add(matrix[i][j]);
}
start++;
end++;
loop++;
}
//找到行和列之间较小的那个数,如果循环了几圈,最后这条边还剩下一个元素,那么必然会剩下一根线。
//找到中间数,掐头去尾输入进去就可以了
if (n < m &&n%2==1) {
//n比较小
int s = (n + 1) / 2 - 1;
for (int k = start; k < m - start; k++) {
list.add(matrix[s][k]);
}
} else if(m <= n &&m%2==1){
int s = (m + 1) / 2 - 1;
for (int k = start; k < n - start; k++) {
list.add(matrix[k][s]);
}
}
return list;
}
}
解法:
和上题一摸一样,只是加入了将这些数据打印出来,那么我们只需要装一个一维数组把集合中的每个元素都倒入就行了,但是要注意力扣会用特殊情况卡我们,即啥元素都没有,因此我们在开始的时候要做一个条件判断。
class Solution {
public int[] spiralOrder(int[][] matrix) {
ArrayList<Integer> list = new ArrayList<>();
int[] arr=new int[0];
if(matrix == null || matrix.length == 0)
return arr;
int n = matrix.length;//有n行
int m = matrix[0].length;//有m列
int start = 0;
int end = 1;
int loop = 0;
int i = 0, j = 0;//i 行 j列
while (loop < n / 2 && loop < m / 2) {
//上边
for (j = start; j < m - end; j++) {
list.add(matrix[start][j]);
}
//右边
for (i = start; i < n - end; i++) {
list.add(matrix[i][j]);
}
//下面
for (; j >= end; j--) {
list.add(matrix[i][j]);
}
//左边
for (; i >= end; i--) {
list.add(matrix[i][j]);
}
start++;
end++;
loop++;
}
//找到行和列之间较小的那个数,如果循环了几圈,最后这条边还剩下一个元素,那么必然会剩下一根线。
//找到中间数,掐头去尾输入进去就可以了
if (n < m &&n%2==1) {
//n比较小
int s = (n + 1) / 2 - 1;
for (int k = start; k < m - start; k++) {
list.add(matrix[s][k]);
}
} else if(m <= n &&m%2==1){
int s = (m + 1) / 2 - 1;
for (int k = start; k < n - start; k++) {
list.add(matrix[k][s]);
}
}
int[] arr1=new int[n*m];
for(int p=0;p<n*m;p++){
arr1[p]=list.get(p);
}
return arr1;
}
}