簡書是一個不錯的平臺,可是種類繁雜,畢竟不是一個專屬于程序員的博客平臺,一直很猶豫是否要把博客從CSDN轉移到這里來。最終還是抵擋不了平臺的誘惑啊。不過說到底,寫在哪里都一樣,寫下來能夠加深自己的印象,同時能夠給一些要學的人一些干貨,何樂而不為。那么,就從一道算法題目開始吧。
順時針填充矩陣
題目:
給出一個二維數組,要求按照順時針將二維數組從1~n填充。
例如:4*4的二維數組,填充之后為:
1 2 3 4 12 13 14 5 11 16 15 6 10 9 8 7
題解:
這道題的解題思路有很多,我只在這里說明一種解法:使用回溯算法求解。所謂回溯算法,實際上是一種向前探索的思路。它會在求解的時候向前探索,把可能出現的情況作為路徑,當這條路無法得到結果時,它會回過頭,探索下一條可能出現的情況。
那么思路如下:首先,矩陣要實現順時針填充,必須要有一個控制方向的“方向盤”。如例子中的矩陣,當一開始向前填充數字的時候,沒有方向的控制,結果只能是下標越界。當有了“方向盤”之后,數字的填充還需要第二個東西,就是“轉彎指示器”。當數字填充到數組邊界時,“轉彎指示器”會提醒“方向盤”轉彎。第三,也就是在數組填充完成后,停止的判斷了。
我們可以把以上思路先用偽代碼表示如下
//0、初始的方向為向右,開始坐標為(1,1)
//1、當前坐標為(x,y),方向為:dir。“填充者”開始工作,填充數字。
向坐標(x,y)填入當前數字。
//2、轉彎指示器和停止判斷器開始工作,判斷是否到達邊界需要轉彎,
以及是否填充完成需要停止。轉彎,執行第5步;停止,執行return。
否則坐標沿著方向指向向接下來的位置移動,
即改變(x,y),然后執行第1步。
//4、轉彎:方向順時針改變一步,然后然后坐標按照當前更改過的方向移動,執行步驟1。
那么,“轉彎指示器”如何設置呢?
我們可以設置這樣一個數組:
int move[][] = {{0,1},{1,0},{0,-1},{-1,0}};
以及這樣一個指針下標:
int direction = 0;
當direction的值為0,1,2,3時,分別對應move數組的4個一維數組,用以表示右、下、左、上四個方向。那么如何在程序中使用這個方向指示器呢?完整代碼如下:
import java.util.Scanner;
public class Main {
public static void main(String []args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
//輸入數字n,設置n*n的數組
CreateA(n);
}
public static void CreateA(int n){
//初始化矩陣為長寬n+2的二維數組,最外層一圈填值為0,其余為-1
int[][] a = new int[n+2][n+2];
for (int i = 1; i < a.length-1; i++) {
for (int j = 1; j < a[i].length-1; j++) {
a[i][j] = -1;
}
}
//方向數組 該數組為本算法的關鍵
int move[][] = {{0,1},{1,0},{0,-1},{-1,0}};
int direction = 0;
int k= 1;
Go(k, 1, 1, n, a, move, direction);
//輸出填好的蛇形矩陣
for (int i = 1; i < a.length-1; i++) {
for (int j = 1; j < a[i].length-1; j++) {
System.out.print("\t"+a[i][j]);
}
System.out.println();
}
}
// 填寫矩陣,矩陣最外層的一圈為0,其他值為-1,當遇到-1的時候才給矩陣里填值
public static void Go(int k,int x,int y,int n,int a[][],int move[][],int direction){
a[x][y] = k++;
if(k> n*n)
return;
while(a[x+move[direction][0]][y+move[direction][1]]!= -1){
//方向由 右、下、左、上循環
direction = (direction+1)%4;
}
//x,y為即將走上的下一個格子
x = x+move[direction][0];
y = y+move[direction][1];
Go(k, x, y, n, a, move, direction);
}
}