package com.interview.leetcode.matrix;
/**
* Created_By: stefanie
* Date: 14-11-14
* Time: 下午10:18
*
* 1. rotate an n*n matrix by 90 degrees (clockwise) in place and O(1) space. {@link #rotate(int[][])}
* 2. create a matrix n * m, and it's element placed in spiral order. {@link #spiralMatrix(int, int)}
* 3. given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order. {@link #spiralPrint(int[][])}
* 4. given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in place. {@link #setZeroes(int[][])}
*
* Tricks:
* 1. define a layer, as scan loop, and matrix position is defined using layer, n and m.
* last = a.length - 1 - layer
* four angle is: matrix[layer][layer], matrix[last][layer], matrix[last][last] and matrix[layer][last]
* to avoid duplicate, put/get element as following in one loop
* a b b b b a matrix[layer][layer]
* e c b matrix[layer][layer+1] ~ matrix[layer][last]
* e c c matrix[layer+1][last] ~ matrix[last][last]
* e c d matrix[last][last-1] ~ matrix[last][layer+1]
* e d d d c e matrix[last][layer] ~ matrix[layer+1][layer]
* if last layer and min is odd number didn't copy d and e.
*
* 2. use existing space in matrix as marker
*/
public class MatrixBasicOperation {
public static void rotate(int[][] a){
for(int layer = 0; layer < a.length / 2; layer++){
int last = a.length - 1 - layer; //last element in this layer
for(int i = 0; i < last - layer; i++){
int tmp = a[layer][layer + i];
a[layer][layer + i] = a[last - i][layer];
a[last - i][layer] = a[last][last - i];
a[last][last - i] = a[layer + i][last];
a[layer + i][last] = tmp;
}
}
}
public static int[][] spiralMatrix(int n, int m) {
int counter = 1;
int[][] matrix = new int[n][m];
int min = Math.min(n, m);
for(int layer = 0; layer < (min+1)/2; layer++){
matrix[layer][layer] = counter++;
for(int offset = layer + 1; offset < m - layer; offset++) matrix[layer][offset] = counter++;
for(int offset = layer + 1; offset < n - layer; offset++) matrix[offset][m - 1 - layer] = counter++;
if(layer == (min+1)/2 - 1 && min % 2 == 1) break; //if last layer and min is odd number
for(int offset = m - 2 - layer; offset > layer; offset--) matrix[n - 1 - layer][offset] = counter++;
for(int offset = n - 1 - layer; offset > layer; offset--) matrix[offset][layer] = counter++;
}
return matrix;
}
public static int[] spiralPrint(int[][] matrix){
int n = matrix.length;
int m = matrix[0].length;
int[] array = new int[n * m];
int counter = 0;
int min = Math.min(n, m);
for(int layer = 0; layer < (min+1)/2; layer++){
array[counter++] = matrix[layer][layer];
for(int offset = layer + 1; offset < m - layer; offset++) array[counter++] = matrix[layer][offset];
for(int offset = layer + 1; offset < n - layer; offset++) array[counter++] = matrix[offset][m - 1 - layer];
if(layer == (min+1)/2 - 1 && min % 2 == 1) break; //if last layer and min is odd number
for(int offset = m - 2 - layer; offset > layer; offset--) array[counter++] = matrix[n - 1 - layer][offset];
for(int offset = n - 1 - layer; offset > layer; offset--) array[counter++] = matrix[offset][layer];
}
return array;
}
/**
* Solution:
* 1. Scan the matrix and make the rows and column need be reset.
* 2. Reset the column. To avoid duplicate reset, first reset the rows and mark non-zero rows, every column just reset the non-zero rows.
*
* Time: O(M*N) Space: O(N+M)
*/
public static void setZeroes(int[][] matrix) {
boolean firstRowZero = false;
boolean firstColZero = false;
firstRowZero = scanRow(matrix, 0);
firstColZero = scanCol(matrix, 0);
for(int i = 1; i < matrix.length; i++){
if(scanRow(matrix, i)) matrix[i][0] = 0;
}
for(int i = 1; i < matrix[0].length; i++){
if(scanCol(matrix, i)) matrix[0][i] = 0;
}
for(int i = 1; i < matrix.length; i++){
if(matrix[i][0] == 0) setRow(matrix, i);
}
for(int i = 1; i < matrix[0].length; i++){
if(matrix[0][i] == 0) setCol(matrix, i);
}
if(firstRowZero) setRow(matrix, 0);
if(firstColZero) setCol(matrix, 0);
}
private static boolean scanRow(int[][] matrix, int row){
for(int i = 0; i < matrix[0].length; i++){
if(matrix[row][i] == 0) return true;
}
return false;
}
private static void setRow(int[][] matrix, int row){
for(int i = 0; i < matrix[0].length; i++) matrix[row][i] = 0;
}
private static boolean scanCol(int[][] matrix, int col){
for(int i = 0; i < matrix.length; i++){
if(matrix[i][col] == 0) return true;
}
return false;
}
private static void setCol(int[][] matrix, int col){
for(int i = 0; i < matrix.length; i++) matrix[i][col] = 0;
}
}