這是第三次CCF計算機軟件能力認證考試(2014年12月14日)的一道題目。小編今天有幸免費參加了此次考試。聽說這題是谷歌的筆試題變形??求證明。。html
好了,題外話不囉嗦,看題目java
題目詳細以下:(來源自http://bbs.csdn.net/topics/390953265,好驚奇的帖子,不知道是哪位同窗在考試期間竟然能發帖到CSDN,讓我有幸複製到考試原文。此外http://www.0531s.com/content-53-1928772-1.html有轉發)算法
在圖像編碼的算法中,須要將一個給定的方形矩陣進行Z字形掃描(Zigzag Scan)。給定一個n×n的矩陣,Z字形掃描的過程以下圖所示:
對於下面的4×4的矩陣,
1 5 3 9
3 7 5 6
9 4 6 4
7 3 1 3
對其進行Z字形掃描後獲得長度爲16的序列:
1 5 3 9 7 3 9 5 4 7 3 6 6 4 1 3
請實現一個Z字形掃描的程序,給定一個n×n的矩陣,輸出對這個矩陣進行Z字形掃描的結果。
輸入格式
輸入的第一行包含一個整數n,表示矩陣的大小。
輸入的第二行到第n+1行每行包含n個正整數,由空格分隔,表示給定的矩陣。
輸出格式
輸出一行,包含n×n個整數,由空格分隔,表示輸入的矩陣通過Z字形掃描後的結果。
樣例輸入
4
1 5 3 9
3 7 5 6
9 4 6 4
7 3 1 3
樣例輸出
1 5 3 9 7 3 9 5 4 7 3 6 6 4 1 3
評測用例規模與約定
1≤n≤500,矩陣元素爲不超過1000的正整數。編程
------------------------------------------------------------------------------------------------------------------------------數組
考完試回來上網搜了搜矩陣Z字形掃描,網上很多高手有先進的解法。這裏我就很少說了。你們能夠去百度或者谷歌。編碼
我在這裏分享下我考試時想到的比較直接的解法,略顯笨拙。記得題目給的運算時間和運行空間仍是比較寬鬆的。spa
在CCF認證考試的五道題裏面,該題排在第二的位置,顯然難度不是很大的,不宜戀戰,應當速戰速決。.net
考試當時想到的第一步就是看圖找規律。發現矩陣Z字形掃描從(0,0)位置開始,前進的方向有4個,分別是右、下,左下、右上。不難看出,Z字形掃描向右、向下兩個方向,只前進一步就會變向,改變後的方向因狀況而異;而左下和右上兩個方向則會一直延伸,直至前面沒法繼續直行時再變向爲向右或者向下。code
然而值得注意的時:htm
1.左下方向因沒法繼續直行須要變向時,要先判斷是否能往下走,若不能往下走再往右走;
2.右上方向因沒法繼續直行須要變向時,要先判斷是否能往右走,若不能往右走再往下走。
到這裏能夠總結出:下一步的方向,由上一步的方向以及周圍的狀況(是否臨界)決定。
想到這些,我就想模擬一我的在(0,0)這個位置出發,沿題目要求的路徑走到(n-1,n-1)的位置。因爲下一步的方向須要上一步的方向來參與決策,所以須要引入一個方向變量direction,分別用值1,2,3,4表明4個方向:右,下,左下,右上。編程的時候能夠分解爲兩個步驟:
1.根據上一步的方向以及是否到達邊界位置來決定下一步方向;
2.根據步驟1獲得的方向前進一步,讀取該位置的數字。
循環直至到達終點(n-1, n-1)
說到這裏,相信看下面的代碼就能看懂了(爲了更容易看懂一些,有一部分代碼能夠簡化的沒有簡化)
(CCF認證考試對JAVA語言答題的要求:1.程序入口爲Main類的main方法;2.不能有package;3.輸入System.in,輸出System.out)
import java.util.Scanner; public class Main { //下面四個變量表明四個方向 public static final int RIGHT = 1; //向右走 public static final int DOWN = 2; //向下走 public static final int LEFTDOWN = 3; //向作下走 public static final int RIGHTUP = 4; //向右上走 public static int data[][]; //矩陣 public static void main(String[] args) { new Main().run(); } public static void run(){ //接收輸入 Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); data = new int[n][n]; for(int i = 0; i < n; i++){ for(int j = 0; j < n; j++){ data[i][j] = scanner.nextInt(); } } //從第一個位置開始,x爲橫座標,y爲縱座標,注意x,y在二維數組中的位置 int x = 0; int y = 0; //輸出要求有空格隔開 String result = data[y][x] + " "; //方向變量的初始值 int direction = 0; //下面就開始出發走咯 while( !(x == n-1 && y == n-1) ){//循環直至到達終點(最右下角的位置) //先判斷下一步往哪一個方向走 if(direction == 0){ //爲0說明還沒走出第一步,因此接着應該往右邊走一步 direction = RIGHT; } else if(direction == RIGHT){ //上一次方向向右,下一步應該向左下或者右上 if(x-1 >= 0 && y+1 < n){ //左下可走 direction = LEFTDOWN; } else { //只能走右上了 direction = RIGHTUP; } } else if(direction == DOWN){ //上一次方向向下,下一步應該向左下或者右上 if(x-1 >= 0 && y+1 < n){ //左下可走 direction = LEFTDOWN; } else { //只能走右上了 direction = RIGHTUP; } } else if(direction == LEFTDOWN){ //上一次向左下,若是能夠,下一步應該繼續向左下,不然 向右或者向下走 if(y+1 < n && x-1 >= 0){ //先判斷可否繼續向左下 direction = LEFTDOWN; } else if(y+1 < n){ //而後判斷可否向下走 direction = DOWN; } else { //最後只能向右走了 direction = RIGHT; } } else if(direction == RIGHTUP){ //上一次向右上,若是能夠,下一步應該繼續向右上,不然向右或者下走 if(x+1 < n && y-1 >=0){ //先判斷可否繼續向右上 direction = RIGHTUP; } else if(x+1 < n){ //而後判斷可否向右走 direction = RIGHT; } else{ //最後只能向下走了 direction = DOWN; } } //根據上面肯定的方向來走出下一步 switch(direction){ case RIGHT: x = x+1; break; case DOWN: y = y+1; break; case LEFTDOWN: x = x-1; y = y+1; break; case RIGHTUP: x = x+1; y = y-1; break; } //讀取當前走到位置的數字.注意x和y的位置 result += data[y][x] + " "; } //輸出結果(這裏需不須要去掉最後的空格?沒怎麼玩過ACM,不記得了acc格式控制會不會這麼嚴) System.out.println(result); } }
From:陳祖煌
Blog:http://my.oschina.net/chenzuhuang/blog
轉載必須說明出處
--------------------------------------------------------------------------------------