5×5の2次元配列をスパイラル順に印刷するにはどうすればよいですか?
任意のサイズの配列をスパイラル順に印刷できる数式はありますか?
この考え方は、マトリックスを一連のレイヤー、右上のレイヤー、左下のレイヤーとして扱うことです。マトリックスを螺旋状に印刷するには、これらのマトリックスからレイヤーを剥離し、剥離した部分を印刷し、左の部分の印刷を再帰的に呼び出します。印刷するレイヤーがなくなると、再帰は終了します。
入力行列:
1 2 3 4
5 6 7 8
9 0 1 2
3 4 5 6
7 8 9 1
右上のレイヤーを剥離した後:
1 2 3 4
8
5 6 7 2
9 0 1 6
3 4 5 1
7 8 9
サブマトリックスから左下のレイヤーを剥離した後:
6 7
5 0 1
9 4 5
3
7 8 9
サブマトリックスから右上のレイヤーを剥離した後:
6 7
1
0 5
4
サブマトリックスから左下のレイヤーを剥離した後:
0
4
再帰は終了します。
C関数:
// function to print the top-right peel of the matrix and
// recursively call the print bottom-left on the submatrix.
void printTopRight(int a[][COL], int x1, int y1, int x2, int y2) {
int i = 0, j = 0;
// print values in the row.
for(i = x1; i<=x2; i++) {
printf("%d ", a[y1][i]);
}
// print values in the column.
for(j = y1 + 1; j <= y2; j++) {
printf("%d ", a[j][x2]);
}
// see if more layers need to be printed.
if(x2-x1 > 0) {
// if yes recursively call the function to
// print the bottom left of the sub matrix.
printBottomLeft(a, x1, y1 + 1, x2-1, y2);
}
}
// function to print the bottom-left peel of the matrix and
// recursively call the print top-right on the submatrix.
void printBottomLeft(int a[][COL], int x1, int y1, int x2, int y2) {
int i = 0, j = 0;
// print the values in the row in reverse order.
for(i = x2; i>=x1; i--) {
printf("%d ", a[y2][i]);
}
// print the values in the col in reverse order.
for(j = y2 - 1; j >= y1; j--) {
printf("%d ", a[j][x1]);
}
// see if more layers need to be printed.
if(x2-x1 > 0) {
// if yes recursively call the function to
// print the top right of the sub matrix.
printTopRight(a, x1+1, y1, x2, y2-1);
}
}
void printSpiral(int arr[][COL]) {
printTopRight(arr,0,0,COL-1,ROW-1);
printf("\n");
}
Pythonコード:
import itertools
arr = [[1,2,3,4],
[12,13,14,5],
[11,16,15,6],
[10,9,8,7]]
def transpose_and_yield_top(arr):
while arr:
yield arr[0]
arr = list(reversed(Zip(*arr[1:])))
print list(itertools.chain(*transpose_and_yield_top(arr)))
コードで1つだけfor loop
と再帰なしを使用している人はいないので、貢献したいと思います。
アイデアは次のとおりです。
ポイント(0,0)にカメが立っていることを想像してください。つまり、左上隅で、東(右)に面しています。
それは前進し続けるであり、サインを見るたびに、亀は右に曲がる
したがって、タートルを右向きのポイント(0,0)に配置し、適切な場所に標識を配置すると、タートルは螺旋状に配列を移動します。
問題は「標識をどこに置くか」です。
記号(#でマーク、Oで数字)を配置する場所を見てみましょう。
このようなグリッドの場合: OOOO OOOO OOOO OOOO このような標識: OOO# #O#O O##O #OO# グリッド用 OOO OOO OOO OOO 次のように標識を付けます: OO# ##O O#O #O# そして、次のようなグリッドの場合: #OOOO#O O#OO#OO O#OOO#O #OOOOO#
ポイントが左上にない限り、記号は最も近い水平方向の境界線と最も近い垂直方向の境界線までの距離は同じですの位置にあることがわかります。 -左の部分、上の境界線までの距離は左の境界線までの距離よりも1つ大きい、ポイントが水平方向に中央にある場合は右上、ケースの場合は左上が優先されるポイントは垂直方向に中央揃えです。
これは、最小の(curRow
とheight-1-curRow
)を取得し、次に最小の(curCol
とwidth-1-curCol
)とそれらが同じかどうかを比較してください。ただし、左上、つまり最小値がcurRow
およびcurCol
自体である場合を考慮する必要があります。その場合、それに応じて垂直距離を短くします。
Cコードは次のとおりです。
#include <stdio.h>
int shouldTurn(int row, int col, int height, int width){
int same = 1;
if(row > height-1-row) row = height-1-row, same = 0; // Give precedence to top-left over bottom-left
if(col >= width-1-col) col = width-1-col, same = 0; // Give precedence to top-right over top-left
row -= same; // When the row and col doesn't change, this will reduce row by 1
if(row==col) return 1;
return 0;
}
int directions[4][2] = {{0,1},{1,0},{0,-1},{-1,0}};
void printSpiral(int arr[4][4], int height, int width){
int directionIdx=0, i=0;
int curRow=0, curCol=0;
for(i=0; i<height*width; i++){
printf("%d ",arr[curRow][curCol]);
if(shouldTurn(curRow, curCol, height, width)){
directionIdx = (directionIdx+1)%4;
}
curRow += directions[directionIdx][0];
curCol += directions[directionIdx][1];
}
printf("\n");
}
int main(){
int arr[4][4]= {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
printSpiral(arr, 4, 4);
printSpiral(arr, 3, 4);
}
どの出力:
1 2 3 4 8 12 16 15 14 13 9 5 6 7 11 10 1 2 3 4 8 12 11 10 9 5 6 7
ここに3つの興味深い方法があります
螺旋状に読むことは、ヘビが境界に向かって移動し、境界またはそれ自体にヒットするように扱うことができます(N反復の単一ループであることがエレガントで最も効率的であることがわかります)
ar = [
[ 0, 1, 2, 3, 4],
[15, 16, 17, 18, 5],
[14, 23, 24, 19, 6],
[13, 22, 21, 20, 7],
[12, 11, 10, 9, 8]]
def print_spiral(ar):
"""
assuming a rect array
"""
rows, cols = len(ar), len(ar[0])
r, c = 0, -1 # start here
nextturn = stepsx = cols # move so many steps
stepsy = rows-1
inc_c, inc_r = 1, 0 # at each step move this much
turns = 0 # how many times our snake had turned
for i in range(rows*cols):
c += inc_c
r += inc_r
print ar[r][c],
if i == nextturn-1:
turns += 1
# at each turn reduce how many steps we go next
if turns%2==0:
nextturn += stepsx
stepsy -= 1
else:
nextturn += stepsy
stepsx -= 1
# change directions
inc_c, inc_r = -inc_r, inc_c
print_spiral(ar)
出力:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
再帰的なアプローチは、外側のレイヤーを印刷し、内側の長方形に対して同じ関数を呼び出すことです。
def print_spiral(ar, sr=0, sc=0, er=None, ec=None):
er = er or len(ar)-1
ec = ec or len(ar[0])-1
if sr > er or sc > ec:
print
return
# print the outer layer
top, bottom, left, right = [], [], [], []
for c in range(sc,ec+1):
top.append(ar[sr][c])
if sr != er:
bottom.append(ar[er][ec-(c-sc)])
for r in range(sr+1,er):
right.append(ar[r][ec])
if ec != sc:
left.append(ar[er-(r-sr)][sc])
print " ".join([str(a) for a in top + right + bottom + left]),
# peel next layer of onion
print_spiral(ar, sr+1, sc+1, er-1, ec-1)
最後にこれを行うための小さなスニペットがありますが、効率的ではありませんが楽しいです:)、基本的に一番上の行を印刷し、長方形全体を反時計回りに回転して繰り返します
def print_spiral(ar):
if not ar: return
print " ".join(str(a) for a in ar[0]),
ar = Zip(*[ reversed(row) for row in ar[1:]])
print_spiral(ar)
このプログラムは、任意のn * n行列に対して機能します。
public class circ {
public void get_circ_arr (int n,int [][] a)
{
int z=n;
{
for (int i=0;i<n;i++)
{
for (int l=z-1-i;l>=i;l--)
{
int k=i;
System.out.printf("%d",a[k][l]);
}
for (int j=i+1;j<=z-1-i;j++)
{
int k=i;
{
System.out.printf("%d",a[j][k]);
}
}
for (int j=i+1;j<=z-i-1;j++)
{
int k=z-1-i;
{
System.out.printf("%d",a[k][j]);
}
}
for (int j=z-2-i;j>=i+1;j--)
{
int k=z-i-1;
{
System.out.printf("%d",a[j][k]);
}
}
}
}
}
}
それが役に立てば幸い
Rubyを学んでいたとき、この問題に夢中になりました。これは私ができる最善のことでした:
def spiral(matrix)
matrix.empty? ? [] : matrix.shift + spiral(matrix.transpose.reverse)
end
この Gist のリビジョンをステップバックして、他のソリューションのいくつかをチェックアウトできます。また、私が要点を分岐したリンクに戻ると、他の巧妙な解決策を見つけることができます。複数のエレガントな方法、特にRubyで解決できる本当に興味深い問題。
JavaScriptソリューション:
var printSpiral = function (matrix) {
var i;
var top = 0;
var left = 0;
var bottom = matrix.length;
var right = matrix[0].length;
while (top < bottom && left < right) {
//print top
for (i = left; i < right; i += 1) {
console.log(matrix[top][i]);
}
top++;
//print right column
for (i = top; i < bottom; i += 1) {
console.log(matrix[i][right - 1]);
}
right--;
if (top < bottom) {
//print bottom
for (i = right - 1; i >= left; i -= 1) {
console.log(matrix[bottom - 1][i]);
}
bottom--;
}
if (left < right) {
//print left column
for (i = bottom - 1; i >= top; i -= 1) {
console.log(matrix[i][left]);
}
left++;
}
}
};
シンプルに保つ->
public class spiralMatrix {
public static void printMatrix(int[][] matrix, int rows, int col)
{
int rowStart=0;
int rowEnd=rows-1;
int colStart=0;
int colEnd=col-1;
while(colStart<=colEnd && rowStart<=rowEnd)
{
for(int i=colStart;i<colEnd;i++)
System.out.println(matrix[rowStart][i]);
for(int i=rowStart;i<rowEnd;i++)
System.out.println(matrix[i][colEnd]);
for(int i=colEnd;i>colStart;i--)
System.out.println(matrix[rowEnd][i]);
for(int i=rowEnd;i>rowStart;i--)
System.out.println(matrix[i][colStart]);
rowStart++;
colEnd--;
rowEnd--;
colStart++;
}
}
public static void main(String[] args){
int[][] array={{1,2,3,4},{5,6,7,8}};
printMatrix(array,2,4);
}
}
アイディア:
らせん状に移動するには、4つの異なる方向に移動する必要があります。スパイラルの1つの層が終了したら、マトリックス内を移動する必要があります。合計で、5つのループ、スパイラルのように通過する4つのループ、およびレイヤーを通過する1つのループが必要です。
public void printSpiralForm(int[][] a, int length)
{
for( int i = 0 , j = length-1 ; i < j ; i++ , j-- )
{
for( int k = i ; k < j ; k++ )
{
System.out.print( a[i][k] + " " ) ;
}
for( int k = i ; k < j ; k++ )
{
System.out.print(a[k][j] + " ");
}
for( int k = j ; k > i ; k-- )
{
System.out.print(a[j][k] + " ") ;
}
for( int k = j ; k > i ; k-- )
{
System.out.print( a[k][i] + " " ) ;
}
}
if ( length % 2 == 1 )
{
System.out.println( a[ length/2 ][ length/2 ] ) ;
}
}
文字のマトリックスが指定されている場合、すべての文字を次の順序で印刷するメソッドを実装します。最初に外側の円、次に次の円というように。
public static void printMatrixInSpiral(int[][] mat){
if(mat.length == 0|| mat[0].length == 0){
/* empty matrix */
return;
}
StringBuffer str = new StringBuffer();
int counter = mat.length * mat[0].length;
int startRow = 0;
int endRow = mat.length-1;
int startCol = 0;
int endCol = mat[0].length-1;
boolean moveCol = true;
boolean leftToRight = true;
boolean upDown = true;
while(counter>0){
if(moveCol){
if(leftToRight){
/* printing entire row left to right */
for(int i = startCol; i <= endCol ; i++){
str.append(mat[startRow][i]);
counter--;
}
leftToRight = false;
moveCol = false;
startRow++;
}
else{
/* printing entire row right to left */
for(int i = endCol ; i >= startCol ; i--){
str.append(mat[endRow][i]);
counter--;
}
leftToRight = true;
moveCol = false;
endRow--;
}
}
else
{
if(upDown){
/* printing column up down */
for(int i = startRow ; i <= endRow ; i++){
str.append(mat[i][endCol]);
counter--;
}
upDown = false;
moveCol = true;
endCol--;
}
else
{
/* printing entire col down up */
for(int i = endRow ; i >= startRow ; i--){
str.append(mat[i][startCol]);
counter--;
}
upDown = true;
moveCol = true;
startCol++;
}
}
}
System.out.println(str.toString());
}
1つの解決策には、右、左、上、下の方向、および対応する制限(インデックス)が含まれます。最初の行が印刷され、方向が(右から)下に変わると、行は上限を増やして破棄されます。最後の列が印刷され、方向が左に変わると、列は右側の制限をデクリメントして破棄されます...詳細は自明のCコードで確認できます。
#include <stdio.h>
#define N_ROWS 5
#define N_COLS 3
void print_spiral(int a[N_ROWS][N_COLS])
{
enum {up, down, left, right} direction = right;
int up_limit = 0,
down_limit = N_ROWS - 1,
left_limit = 0,
right_limit = N_COLS - 1,
downcount = N_ROWS * N_COLS,
row = 0,
col = 0;
while(printf("%d ", a[row][col]) && --downcount)
if(direction == right)
{
if(++col > right_limit)
{
--col;
direction = down;
++up_limit;
++row;
}
}
else if(direction == down)
{
if(++row > down_limit)
{
--row;
direction = left;
--right_limit;
--col;
}
}
else if(direction == left)
{
if(--col < left_limit)
{
++col;
direction = up;
--down_limit;
--row;
}
}
else /* direction == up */
if(--row < up_limit)
{
++row;
direction = right;
++left_limit;
++col;
}
}
void main()
{
int a[N_ROWS][N_COLS] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
print_spiral(a);
}
これは私の実装です:
public static void printMatrix(int matrix[][], int M, int N){
int level = 0;
int min = (M < N) ? M:N;
System.out.println();
while(level <= min/2){
for(int j = level; j < N - level - 1; j++){
System.out.print(matrix[level][j] + "\t");
}
for(int i = level; i < M - level - 1; i++) {
System.out.print(matrix[i][N - level - 1] + "\t");
}
for(int j = N - level - 1; j > level; j--){
System.out.print(matrix[M - level - 1][j] + "\t");
}
for(int i = M - level - 1; i > level; i-- ){
System.out.print(matrix[i][level] + "\t");
}
level++;
}
}
複雑さ:シングルトラバース
O(n)
シングルループ複雑さO(n)
の回答を追加してください。私は、マトリックスの左右および左右のトラバース中に、行優先インデックスでそれぞれ1つずつ増減することを観察しました。同様に、上下および上下のトラバースでは、n_cols
。したがって、そのためのアルゴリズムを作成しました。たとえば、行優先インデックスのエントリを持つ(3x5)マトリックスを指定すると、印刷出力は次のようになります。1,2,3,4,5,10,15,14,13,12,11,6,7,8,9
。
------->(+1)
^ 1 2 3 4 5 |
(+n_cols) | 6 7 8 9 10 | (-n_cols)
| 11 12 13 14 15
(-1)<-------
コードソリューション:
#include <iostream>
using namespace std;
int main() {
// your code goes here
bool leftToRight=true, topToBottom=false, rightToLeft=false, bottomToTop=false;
int idx=0;
int n_rows = 3;
int n_cols = 5;
int cnt_h = n_cols, cnt_v = n_rows, cnt=0;
int iter=1;
for (int i=0; i <= n_rows*n_cols + (n_rows - 1)*(n_cols - 1)/2; i++){
iter++;
if(leftToRight){
if(cnt >= cnt_h){
cnt_h--; cnt=0;
leftToRight = false; topToBottom = true;
//cout << "Iter: "<< iter << " break_leftToRight"<<endl;
}else{
cnt++;
idx++;
//cout << "Iter: "<< iter <<" idx: " << idx << " cnt: "<< cnt << " cnt_h: "<< cnt_h<< endl;
cout<< idx << endl;
}
}else if(topToBottom){
if(cnt >= cnt_v-1){
cnt_v--; cnt=0;
leftToRight = false; topToBottom = false; rightToLeft=true;
//cout << "Iter: "<< iter << " break_topToBottom"<<endl;
}else{
cnt++;
idx+=n_cols;
//cout << "Iter: "<< iter << " idx: " << idx << " cnt: "<< cnt << " cnt_v: "<< cnt_h<< endl;
cout << idx <<endl;
}
}else if(rightToLeft){
if(cnt >= cnt_h){
cnt_h--; cnt=0;
leftToRight = false; topToBottom = false; rightToLeft=false; bottomToTop=true;
//cout << "Iter: "<< iter << " break_rightToLeft"<<endl;
//cout<< idx << endl;
}else{
cnt++;
idx--;
//cout << "Iter: "<< iter << " idx: " << idx << " cnt: "<< cnt << " cnt_h: "<< cnt_h<< endl;
cout << idx <<endl;
}
}else if(bottomToTop){
if(cnt >= cnt_v-1){
cnt_v--; cnt=0;
leftToRight = true; topToBottom = false; rightToLeft=false; bottomToTop=false;
//cout << "Iter: "<< iter << " break_bottomToTop"<<endl;
}else{
cnt++;
idx-=n_cols;
//cout << "Iter: "<< iter << " idx: " << idx << " cnt: "<< cnt << " cnt_v: "<< cnt_h<< endl;
cout<< idx << endl;
}
}
//cout << i << endl;
}
return 0;
}
void slashTransposeFlip(int[][] m){
if( m.length * m[0].length == 1){ //only one element left
System.out.print(m[0][0]);
}else{
//print the top row
for(int a:m[0]){System.out.print(a+" ");}
//slash the top row from the matrix.
int[][] n = Arrays.copyOfRange(m,1,m.length);
int[][] temp = n;
int rows = temp.length;
int columns = temp[0].length;
//invert rows and columns and create new array
n = new int[columns][rows];
//transpose
for(int x=0;x<rows;x++)
for(int y=0;y<columns;y++)
n[y][x] = temp[x][y];
//flipping time
for (int i = 0; i < n.length / 2; i++) {
int[] t = n[i];
n[i] = n[n.length - 1 - i];
n[n.length - 1 - i] = t;
}
//recursively call again the reduced matrix.
slashTransposeFlip(n);
}
}
int N = Integer.parseInt(args [0]);
// create N-by-N array of integers 1 through N
int[][] a = new int[N][N];
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
a[i][j] = 1 + N*i + j;
// spiral
for (int i = N-1, j = 0; i > 0; i--, j++) {
for (int k = j; k < i; k++) System.out.println(a[j][k]);
for (int k = j; k < i; k++) System.out.println(a[k][i]);
for (int k = i; k > j; k--) System.out.println(a[i][k]);
for (int k = i; k > j; k--) System.out.println(a[k][j]);
}
// special case for middle element if N is odd
if (N % 2 == 1) System.out.println(a[(N-1)/2][(N-1)/2]);
}
}
Python3で問題を解決しました。ほとんどすべてのEdgeケースを通過しています。
def spiralOrder(self, matrix):
r = len(matrix)
if r == 0:
return []
c = len(matrix[0])
result = []
x = 0; y = 0
while x< r and y<c:
for i in range(y,c):
result.append(matrix[x][i])
x+=1
for i in range(x,r):
result.append(matrix[i][c-1])
c-=1
if x < r:
for i in range(c-1,y-1,-1):
result.append(matrix[r-1][i])
r -=1
if y <c :
for i in range(r-1,x-1,-1):
result.append(matrix[i][y])
y+=1
return result
この質問はこれに関連しています: PHPでのマトリックス配置の問題
提示された答えはうまくいくように見えますが、理解するのは複雑です。これを解決する非常に簡単な方法は、分割して征服することです。つまり、Edgeを読み取った後、それを削除すると、次の読み取りがはるかに簡単になります。 PHP以下の完全なソリューションをご覧ください。
#The source number matrix
$source[0] = array(1, 2, 3, 4);
$source[1] = array(5, 6, 7, 8);
$source[2] = array(9, 10, 11, 12);
$source[3] = array(13, 14, 15, 16);
$source[4] = array(17, 18, 19, 20);
#Get the spiralled numbers
$final_spiral_list = get_spiral_form($source);
print_r($final_spiral_list);
function get_spiral_form($matrix)
{
#Array to hold the final number list
$spiralList = array();
$result = $matrix;
while(count($result) > 0)
{
$resultsFromRead = get_next_number_circle($result, $spiralList);
$result = $resultsFromRead['new_source'];
$spiralList = $resultsFromRead['read_list'];
}
return $spiralList;
}
function get_next_number_circle($matrix, $read)
{
$unreadMatrix = $matrix;
$rowNumber = count($matrix);
$colNumber = count($matrix[0]);
#Check if the array has one row or column
if($rowNumber == 1) $read = array_merge($read, $matrix[0]);
if($colNumber == 1) for($i=0; $i<$rowNumber; $i++) array_Push($read, $matrix[$i][0]);
#Check if array has 2 rows or columns
if($rowNumber == 2 || ($rowNumber == 2 && $colNumber == 2))
{
$read = array_merge($read, $matrix[0], array_reverse($matrix[1]));
}
if($colNumber == 2 && $rowNumber != 2)
{
#First read left to right for the first row
$read = array_merge($read, $matrix[0]);
#Then read down on right column
for($i=1; $i<$rowNumber; $i++) array_Push($read, $matrix[$i][1]);
#..and up on left column
for($i=($rowNumber-1); $i>0; $i--) array_Push($read, $matrix[$i][0]);
}
#If more than 2 rows or columns, pick up all the Edge values by spiraling around the matrix
if($rowNumber > 2 && $colNumber > 2)
{
#Move left to right
for($i=0; $i<$colNumber; $i++) array_Push($read, $matrix[0][$i]);
#Move top to bottom
for($i=1; $i<$rowNumber; $i++) array_Push($read, $matrix[$i][$colNumber-1]);
#Move right to left
for($i=($colNumber-2); $i>-1; $i--) array_Push($read, $matrix[$rowNumber-1][$i]);
#Move bottom to top
for($i=($rowNumber-2); $i>0; $i--) array_Push($read, $matrix[$i][0]);
}
#Now remove these Edge read values to create a new reduced matrix for the next read
$unreadMatrix = remove_top_row($unreadMatrix);
$unreadMatrix = remove_right_column($unreadMatrix);
$unreadMatrix = remove_bottom_row($unreadMatrix);
$unreadMatrix = remove_left_column($unreadMatrix);
return array('new_source'=>$unreadMatrix, 'read_list'=>$read);
}
function remove_top_row($matrix)
{
$removedRow = array_shift($matrix);
return $matrix;
}
function remove_right_column($matrix)
{
$neededCols = count($matrix[0]) - 1;
$finalMatrix = array();
for($i=0; $i<count($matrix); $i++) $finalMatrix[$i] = array_slice($matrix[$i], 0, $neededCols);
return $finalMatrix;
}
function remove_bottom_row($matrix)
{
unset($matrix[count($matrix)-1]);
return $matrix;
}
function remove_left_column($matrix)
{
$neededCols = count($matrix[0]) - 1;
$finalMatrix = array();
for($i=0; $i<count($matrix); $i++) $finalMatrix[$i] = array_slice($matrix[$i], 1, $neededCols);
return $finalMatrix;
}
function spiral(a) {
var s = [];
while (a.length) {
// concat 1st row, Push last cols, rotate 180 (reverse inner/outer)...
s = s.concat(a.shift());
a = a
.map(function(v) {
s.Push(v.pop());
return v.reverse();
})
.reverse();
}
return s;
}
var arr = [
[1, 2, 3, 4],
[12, 13, 14, 5],
[11, 16, 15, 6],
[10, 9, 8, 7]
];
console.log(spiral(arr));// -> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
arr = [
[0, 1, 2, 3, 4],
[15, 16, 17, 18, 5],
[14, 23, 24, 19, 6],
[13, 22, 21, 20, 7],
[12, 11, 10, 9, 8]
];
console.log(spiral(arr));// -> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
これは私が考えることができるCの再帰バージョンです:-
void printspiral (int[][100],int, int, int, int);
int main()
{
int r,c, i, j;
printf ("Enter the dimensions of the matrix");
scanf("%d %d", &r, &c);
int arr[r][100];
int min = (r<c?r:c);
if (min%2 != 0) min = min/2 +1;
for (i = 0;i<r; i++)
for (j = 0; j<c; j++)
scanf ("%d",&arr[i][j]);
printspiral(arr,0,r,c,min );
}
void printspiral (int arr[][100], int i, int j, int k, int min)
{
int a;
for (a = i; a<k;a++)
printf("%d\n", arr[i][a]);
for (a=i+1;a<j;a++)
printf ("%d\n", arr[a][k-1]);
for (a=k-2; a>i-1;a--)
printf("%d\n", arr[j-1][a]);
for (a=j-2; a>i; a--)
printf("%d\n", arr[a][i]);
if (i < min)
printspiral(arr,i+1, j-1,k-1, min);
}
これが私の解決策です。私が間違っている場合は修正してください。
class Spiral:
def spiralOrder(self, A):
result = []
c = []
c.append(A[0])
b = A[1:]
while len(b) > 0:
b = self.rotate(b)
c.append(b[0])
b = b[1:]
for item in c:
for fitem in item:
print fitem,
result.append(fitem)
return result
def rotate(self,a):
b = []
l = Zip(*a)
for i in xrange(len(l)-1,-1,-1):
b.append(list(l[i]))
return b
if __== '__main__':
a = [[1, 2, 3,3], [4, 5, 6,6], [7, 8, 9,10]]
s = Spiral()
s.spiralOrder(a)
2-Dマトリックスを印刷するには、マトリックスを長方形および/または小さな長方形が大きな長方形に収まる線の構成と見なし、各レイヤーで左上の要素から開始する長方形を形成するマトリックスの境界を取ります;一度これを行うと、小さな長方形の次のレイヤーに進みます。長方形がない場合は、印刷する線、水平または垂直にする必要があります。サンプルマトリックスHTHを使用してコードを貼り付けました。
#include <stdio.h>
int a[2][4] = { 1, 2 ,3, 44,
8, 9 ,4, 55 };
void print(int, int, int, int);
int main() {
int row1, col1, row2, col2;
row1=0;
col1=0;
row2=1;
col2=3;
while(row2>=row1 && col2>=col1)
{
print(row1, col1, row2, col2);
row1++;
col1++;
row2--;
col2--;
}
return 0;
}
void print(int row1, int col1, int row2, int col2) {
int i=row1;
int j=col1;
/* This is when single horizontal line needs to be printed */
if( row1==row2 && col1!=col2) {
for(j=col1; j<=col2; j++)
printf("%d ", a[i][j]);
return;
}
/* This is when single vertical line needs to be printed */
if( col1==col2 && row1!=row2) {
for(i=row1; j<=row2; i++)
printf("%d ", a[i][j]);
return;
}
/* This is reached when there is a rectangle to be printed */
for(j=col1; j<=col2; j++)
printf("%d ", a[i][j]);
for(j=col2,i=row1+1; i<=row2; i++)
printf("%d ", a[i][j]);
for(i=row2,j=col2-1; j>=col1; j--)
printf("%d ", a[i][j]);
for(j=col1,i=row2-1; i>row1; i--)
printf("%d ", a[i][j]);
}
らせんは、水平および垂直セグメントの順序付けられたセットで構成されていると想像できます。 次の各水平セグメントは前の水平セグメントよりも1つの要素が短く、次の各垂直セグメントは前の垂直セグメントよりも1つの要素が短いであることがわかります。各次のセグメントは、前のセグメントが終了するセルに隣接するセルで始まります。時計回りにらせんを構成すると仮定します。最初の水平セグメントの長さは、特定のマトリックスの列数に等しくなります。最初の垂直セグメントの長さは、指定されたマトリックスの行数から1を引いたものに等しくなります。これらの観測を使用すると、追加のメモリやO(NxM)
実行時間の再帰なしに、NxM行列を走査できます。
public static void VisitBySpiral<T>(T[,] matrix, Action<T> onVisit)
{
var spiralWidth = matrix.GetLength(1);
var spiralHeight = matrix.GetLength(0);
var row = 0;
var column = 0;
var step = +1;
while (spiralWidth > 0 && spiralHeight > 0)
{
var horizontalSteps = spiralWidth;
while (horizontalSteps-- > 0)
{
onVisit(matrix[row, column]);
if (horizontalSteps > 0)
{
column += step;
}
}
// Move to the cell where next vertical segment starts.
row += step;
--spiralHeight;
var verticalSteps = spiralHeight;
while (verticalSteps-- > 0)
{
onVisit(matrix[row, column]);
if (verticalSteps > 0)
{
row += step;
}
}
--spiralWidth;
step *= -1;
// Move to the cell where next horizontal segment starts.
column += step;
}
}
これはJava任意のm x n行列の実装です。ここで、rows =行数およびColumn =列数
public static void printSpiral(int rows, int columns, int a[][])
{
int i, k = 0, l = 0;
/* k - starting row index
l - starting column index
*/
while (k < rows && l < columns)
{
/* Print the first row from the remaining rows */
for (i = l; i < columns; ++i)
{
System.out.println(a[k][i]);
}
k++;
/* Print the last column from the remaining columns */
for (i = k; i < rows; ++i)
{
System.out.println(a[i][columns-1]);
}
columns--;
/* Print the last row from the remaining rows */
if ( k < rows)
{
for (i = columns-1; i >= l; --i)
{
System.out.println(a[rows-1][i]);
}
rows--;
}
/* Print the first column from the remaining columns */
if (l < columns)
{
for (i = rows-1; i >= k; --i)
{
System.out.println(a[i][l]);
}
l++;
}
}
}
public class SpiralPrint{
//print the elements of matrix in the spiral order.
//my idea is to use recursive, for each outer loop
public static void printSpiral(int[][] mat, int layer){
int up = layer;
int buttom = mat.length - layer - 1;
int left = layer;
int right = mat[0].length - layer - 1;
if(up > buttom+1 || left > right + 1)
return; // termination condition
//traverse the other frame,
//print up
for(int i = left; i <= right; i ++){
System.out.print( mat[up][i]+ " " );
}
//print right
for(int i = up + 1; i <=buttom; i ++){
System.out.print(mat[i][right] + " ");
}
//print buttom
for(int i = right - 1; i >= left; i --){
System.out.print(mat[buttom][i] + " ");
}
//print left
for(int i = buttom - 1; i > up; i --){
System.out.print(mat[i][left] + " ");
}
//recursive call for the next level
printSpiral(mat, layer + 1);
}
public static void main(String[] args){
int[][] mat = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}, {13,14,15,16}};
int[][] mat2 = {{1,2,3}, {4,5,6}, {7,8,9}, {10,11,12}};
SpiralPrint.printSpiral(mat2,0);
return;
}
}
Iteratorを使用した私のアプローチを次に示します。これはほぼ同じ問題を解決することに注意してください。ここに完全なコードがあります: https://github.com/rdsr/algorithms/blob/master/src/jvm/misc/FillMatrix.Java
import Java.util.Iterator;
class Pair {
final int i;
final int j;
Pair(int i, int j) {
this.i = i;
this.j = j;
}
@Override
public String toString() {
return "Pair [i=" + i + ", j=" + j + "]";
}
}
enum Direction {
N, E, S, W;
}
class SpiralIterator implements Iterator<Pair> {
private final int r, c;
int ri, ci;
int cnt;
Direction d; // current direction
int level; // spiral level;
public SpiralIterator(int r, int c) {
this.r = r;
this.c = c;
d = Direction.E;
level = 1;
}
@Override
public boolean hasNext() {
return cnt < r * c;
}
@Override
public Pair next() {
final Pair p = new Pair(ri, ci);
switch (d) {
case E:
if (ci == c - level) {
ri += 1;
d = changeDirection(d);
} else {
ci += 1;
}
break;
case S:
if (ri == r - level) {
ci -= 1;
d = changeDirection(d);
} else {
ri += 1;
}
break;
case W:
if (ci == level - 1) {
ri -= 1;
d = changeDirection(d);
} else {
ci -= 1;
}
break;
case N:
if (ri == level) {
ci += 1;
level += 1;
d = changeDirection(d);
} else {
ri -= 1;
}
break;
}
cnt += 1;
return p;
}
private static Direction changeDirection(Direction d) {
switch (d) {
case E:
return Direction.S;
case S:
return Direction.W;
case W:
return Direction.N;
case N:
return Direction.E;
default:
throw new IllegalStateException();
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
public class FillMatrix {
static int[][] fill(int r, int c) {
final int[][] m = new int[r][c];
int i = 1;
final Iterator<Pair> iter = new SpiralIterator(r, c);
while (iter.hasNext()) {
final Pair p = iter.next();
m[p.i][p.j] = i;
i += 1;
}
return m;
}
public static void main(String[] args) {
final int r = 19, c = 19;
final int[][] m = FillMatrix.fill(r, c);
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
System.out.print(m[i][j] + " ");
}
System.out.println();
}
}
}
誰かが興味があるならJavaコード。
入力:
4
1 2 3 4
5 6 7 8
9 1 2 3
4 5 6 7
出力:1 2 3 4 8 3 7 6 5 4 9 5 6 7 2 1
public class ArraySpiralPrinter {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(); //marrix size
//read array
int[][] ar = new int[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
ar[i][j] = sc.nextInt();
}
}
printTopRight(0, 0, n - 1, n - 1, ar);
}
//prints top and right layers.
//(x1,y1) to (x1, y2) - top layer & (x1,y2) to (x2, y2)
private static void printTopRight(int x1, int y1, int x2, int y2, int[][] ar) {
//print row values - top
for (int y = y1; y <= y2; y++) {
System.out.printf("%d ", ar[x1][y]);
}
//print column value - right
for (int x = x1 + 1; x <= x2; x++) {
System.out.printf("%d ", ar[x][y2]);
}
//are there any remaining layers
if (x2 - x1 > 0) {
//call printBottemLeft
printBottomLeft(x1 + 1, y1, x2, y2 - 1, ar);
}
}
//prints bottom and left layers in reverse order
//(x2,y2) to (x2, y1) - bottom layer & (x2,y1) to (x1, y1)
private static void printBottomLeft(int x1, int y1, int x2, int y2, int[][] ar) {
//print row values in reverse order - bottom
for (int y = y2; y >= y1; y--) {
System.out.printf("%d ", ar[x2][y]);
}
//print column value in reverse order - left
for (int x = x2-1; x >= x1; x--) {
System.out.printf("%d ", ar[x][y1]);
}
//are there any remaining layers
if (x2 - x1 > 0) {
printTopRight(x1, y1 + 1, x2 - 1, y2, ar);
}
}
}
http://www.technicalinterviewquestions.net/2009/03/print-2d-array-matrix-spiral-order.html
ここに上記の答えの最良の説明があります:)ダイアグラムとともに:)
関連するテストケースを含むC#の作業コード。 n x m
マトリックス。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MatrixSpiralPrint
{
class Matrix
{
int[,] mat;
public Matrix(int[,] matrix)
{
mat = matrix;
}
void printHelper(int x)
{
Console.Write(string.Format("{0} ", x));
}
// print the top right of the matrix and
// recursively call the print bottom left on the submatrix.
void printTopRight(int colStart, int rowStart, int colEnd, int rowEnd)
{
int i = 0, j = 0;
// print Top row.
for (i = colStart; i <= colEnd; i++)
{
printHelper(mat[rowStart, i]);
}
// print Right column.
for (j = rowStart + 1; j <= rowEnd; j++)
{
printHelper(mat[j, colEnd]);
}
// Recursion base case: see if more layers need to be printed.
if (colEnd - colStart > 0 && rowStart!=rowEnd)
{
// print the bottom left of the sub matrix.
printBottomLeft(colStart, rowStart + 1, colEnd - 1, rowEnd);
}
}
// print the bottom left peel of the matrix and
// recursively call the print top right on the submatrix.
void printBottomLeft(int colStart, int rowStart, int colEnd, int rowEnd)
{
int i = 0, j = 0;
// print Bottom row in reverse order.
for (i = colEnd; i >= colStart; i--)
{
printHelper(mat[rowEnd, i]);
}
// print Left column in reverse order.
for (j = rowEnd - 1; j >= rowStart; j--)
{
printHelper(mat[j, colStart]);
}
// Recursion base case: see if more layers need to be printed.
if (colEnd - colStart > 0)
{
// print the top right of the sub matrix.
printTopRight(colStart + 1, rowStart, colEnd, rowEnd - 1);
}
}
void printMatrix()
{
int rowLength = mat.GetLength(0);
int colLength = mat.GetLength(1);
Console.WriteLine("Test Case");
for (int i = 0; i < rowLength; i++)
{
for (int j = 0; j < colLength; j++)
{
Console.Write(string.Format("{0} ", mat[i, j]));
}
Console.Write(Environment.NewLine + Environment.NewLine);
}
}
public void printSpiral()
{
var maxRowIndex = mat.GetUpperBound(0);
var maxColIndex = mat.GetUpperBound(1);
printMatrix();
Console.WriteLine("Spiral Print");
printTopRight(0, 0, maxColIndex, maxRowIndex);
Console.WriteLine("\n---------------------------------");
}
}
class Program
{
static void Main(string[] args)
{
var matrix = new int[,] {
{ 1,2,3,4,5},
{ 6,7,8,9,10},
{ 11,12,13,14,15},
{ 16,17,18,19,20},
{ 21,22,23,24,25}
};
var mat = new Matrix(matrix);
mat.printSpiral();
matrix = new int[,] {
{ 1,2,3,4},
{ 5,6,7,8},
{ 9,10,11,12}
};
mat = new Matrix(matrix);
mat.printSpiral();
matrix = new int[,] {
{ 1,2,3},
{ 4,5,6},
{ 7,8,9},
{ 10,11,12},
};
mat = new Matrix(matrix);
mat.printSpiral();
matrix = new int[,] {
{ 1,2 }
};
mat = new Matrix(matrix);
mat.printSpiral();
matrix = new int[,] {
{ 1},
{ 2}
};
mat = new Matrix(matrix);
mat.printSpiral();
}
}
}
承認された回答はどのn x m
マトリックス。このコードは、受け入れられた回答で@codaddictによって投稿されたコードを使用してC#に移植されます。再帰ベースケースを修正しました。
C#での私のソリューションは次のとおりです。
public static void PrintSpiral(int[][] matrix, int n)
{
if (matrix == null)
{
return;
}
for (int layer = 0; layer < Math.Ceiling(n / 2.0); layer++)
{
var start = layer;
var end = n - layer - 1;
var offset = end - 1;
Console.Write("Layer " + layer + ": ");
// Center case
if (start == end)
{
Console.Write(matrix[start][start]);
}
// Top
for (int i = start; i <= offset; i++)
{
Console.Write(matrix[start][i] + " ");
}
// Right
for (int i = start; i <= offset; i++)
{
Console.Write(matrix[i][end] + " ");
}
// Bottom
for (int i = end; i > start; i--)
{
Console.Write(matrix[end][i] + " ");
}
// Left
for (int i = end; i > start; i--)
{
Console.Write(matrix[i][start] + " ");
}
Console.WriteLine();
}
}
Javaでの私の実装は次のとおりです。
public class SpiralPrint {
static void spiral(int a[][],int x,int y){
//If the x and y co-ordinate collide, break off from the function
if(x==y)
return;
int i;
//Top-left to top-right
for(i=x;i<y;i++)
System.out.println(a[x][i]);
//Top-right to bottom-right
for(i=x+1;i<y;i++)
System.out.println(a[i][y-1]);
//Bottom-right to bottom-left
for(i=y-2;i>=x;i--)
System.out.println(a[y-1][i]);
//Bottom left to top-left
for(i=y-2;i>x;i--)
System.out.println(a[i][x]);
//Recursively call spiral
spiral(a,x+1,y-1);
}
public static void main(String[] args) {
int a[][]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
spiral(a,0,4);
/*Might be implemented without the 0 on an afterthought, all arrays will start at 0 anyways. The second parameter will be the dimension of the array*/
}
}
//shivi..coding is adictive!!
#include<shiviheaders.h>
#define R 3
#define C 6
using namespace std;
void PrintSpiral(int er,int ec,int arr[R][C])
{
int sr=0,sc=0,i=0;
while(sr<=er && sc<=ec)
{
for(int i=sc;i<=ec;++i)
cout<<arr[sr][i]<<" ";
++sr;
for(int i=sr;i<=er;++i)
cout<<arr[i][ec]<<" ";
ec--;
if(sr<=er)
{
for(int i=ec;i>=sc;--i)
cout<<arr[er][i]<<" ";
er--;
}
if(sc<=ec)
{
for(int i=er;i>=sr;--i)
cout<<arr[i][sc]<<" ";
++sc;
}
}
}
int main()
{
int a[R][C] = { {1, 2, 3, 4, 5, 6},
{7, 8, 9, 10, 11, 12},
{13, 14, 15, 16, 17, 18}
};
PrintSpiral(R-1, C-1, a);
}
public static void printSpiral1(int array[][],int row,int col){
int rowStart=0,colStart=0,rowEnd=row-1,colEnd=col-1;
int i;
while(rowStart<=rowEnd && colStart<= colEnd){
for(i=colStart;i<=colEnd;i++)
System.out.print(" "+array[rowStart][i]);
for(i=rowStart+1;i<=rowEnd;i++)
System.out.print(" "+array[i][colEnd]);
for(i=colEnd-1;i>=colStart;i--)
System.out.print(" "+array[rowEnd][i]);
for(i=rowEnd-1;i>=rowStart+1;i--)
System.out.print(" "+array[i][colStart]);
rowStart++;
colStart++;
rowEnd--;
colEnd--;
}
}
// Program to print a matrix in spiral order
#include <stdio.h>
int main(void) {
// your code goes here
int m,n,i,j,k=1,c1,c2,r1,r2;;
scanf("%d %d",&m,&n);
int a[m][n];
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
scanf("%d",&a[i][j]);
}
}
r1=0;
r2=m-1;
c1=0;
c2=n-1;
while(k<=m*n)
{
for(i=c1;i<=c2;i++)
{
k++;
printf("%d ",a[r1][i]);
}
for(j=r1+1;j<=r2;j++)
{
k++;
printf("%d ",a[j][c2]);
}
for(i=c2-1;i>=c1;i--)
{
k++;
printf("%d ",a[r2][i]);
}
for(j=r2-1;j>=r1+1;j--)
{
k++;
printf("%d ",a[j][c1]);
}
c1++;
c2--;
r1++;
r2--;
}
return 0;
}
#include <iostream>
using namespace std;
const int MAX=100;
int main(void)
{
int a[MAX][MAX],i,j,lower,upper,k,n=0,am=0;
cout<<"enter number or size of matrix \n"<<endl;
cin>>n;
// assigning the value
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
a[i][j]=am+1;
}
i=0;
j=0;
lower=0,upper=n-1;
for(k=0;k<(n*n);k++)
{
cout<<a[i][j]<<"\t";
if((i==lower)&&(j<upper))
j++;
else if((j==upper)&&(i<lower))
j--;
else if((j==lower)&&(i>lower))
i--;
if((a[i][j]==a[lower][i]))
{
lower++;
upper--;
i++;
j++;
}
}
return 0;
}
行x列が指定された2D配列行列の完全な純粋なCプログラム。
#include <stdio.h>
void printspiral(int *p,int r, int c) {
int i=0,j=0,m=1,n=0;
static int firstrun=1,gCol;
if (!p||r<=0||c<=0)
return ;
if(firstrun) {
gCol=c;
firstrun=0;
}
for(i=0,j=0;(0<=i && i<c)&&(0<=j && j<r);i+=m,j+=n) {
printf(" %d",p[i+j*gCol]);
if (i==0 && j==1 && (i+1)!=c) break;
else if (i+1==c && !j) {m=0;n=1;}
else if (i+1==c && j+1==r && j) {n=0;m=-1;}
else if (i==0 && j+1==r && j) {m=0;n=-1;}
}
printspiral(&p[i+j*gCol+1],r-2,c-2);
firstrun=1;
printf("\n");
}
int main() {
int a[3][3]={{0,1,2},{3,4,5},{6,7,8}};
int b[3][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11}};
int c[4][3]={{0,1,2},{3,4,5},{6,7,8},{9,10,11}};
int d[3][1]={{0},{1},{2}};
int e[1][3]={{0,1,2}};
int f[1][1]={{0}};
int g[5][5]={{0,1,2,3,4},{5,6,7,8,9},{10,11,12,13,14},{15,16,17,18,19},{20,21,22,23,24}};
printspiral(a,3,3);
printspiral(b,3,4);
printspiral(c,4,3);
printspiral(d,3,1);
printspiral(e,1,3);
printspiral(f,1,1);
printspiral(g,5,5);
return 0;
}