二维数组常见题目
顺时针打印矩阵
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
示例 1:
1 2 输入:matrix = [[1,2,3],[4,5,6],[7,8,9]] 输出:[1,2,3,6,9,8,7,4,5]
思路:定义两个点:左上角和右下角。这两个点每次都在同一层的边框上,只要确定了这两个点,就可以顺时针方向遍历这一层框的元素(四条边上的元素)。遍历完毕后再将左上角向右下方向移动一格 ,右下角向左上方向移动一格。从而使得边框向内层收缩,然后重复上一步骤即可。
例如下图使用不同颜色代表每一层的各个边,两个箭头代表两个边界点的移动方向:
其中,在打印当前层的边框时,需要特别注意 :分别打印四条边时,每次循环的终止是在该边的另一端点(另一条边的起点)的前一个位置,不能将该端点也打印,而应该将其作为下一条边的起点时被打印。以上图为例,最外层的遍历每次只能遍历四个格子,不能遍历到该行/列的最后一个,因为这一个元素是下一条边的起点,不能提前遍历了。
代码:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 public class PrintMatrixSpiralOrder { public static void printMatrixSpiralOrder (int [][] matrix) { if (matrix == null || matrix.length < 1 ) { return ; } int topRow = 0 ; int topCol = 0 ; int downRow = matrix.length - 1 ; int downCol = matrix[0 ].length - 1 ; while (topRow <= downRow && topCol <= downCol) { printEdge(matrix, topRow++, topCol++, downRow--, downCol--); } } public static void printEdge (int [][] matrix, int topRow, int topCol, int downRow, int downCol) { if (topRow > downRow || topCol > downCol) { return ; } if (topRow == downRow) { while (topCol <= downCol) { System.out.print(matrix[topRow][topCol] + ' ' ); topCol++; } } else if (topCol == downCol) { while (topRow <= downRow) { System.out.print(matrix[topRow][topCol] + ' ' ); topRow++; } } else { int curRow = topRow; int curCol = topCol; while (curCol < downCol) { System.out.print(matrix[curRow][curCol] + " " ); curCol++; } while (curRow < downRow) { System.out.print(matrix[curRow][curCol] + " " ); curRow++; } while (curCol > topCol) { System.out.print(matrix[curRow][curCol] + " " ); curCol--; } while (curRow > topRow) { System.out.print(matrix[curRow][curCol] + " " ); curRow--; } } } public static void main (String[] args) { int [][] matrix = { { 1 , 2 , 3 , 4 }, { 5 , 6 , 7 , 8 }, { 9 , 10 , 11 , 12 }, { 13 , 14 , 15 , 16 } }; printMatrixSpiralOrder(matrix); } }
顺时针旋转正方形
给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。你必须在原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要使用另一个矩阵来旋转图像。
方法一:由外向内层层遍历,交换每层内的四个对应位置
同样可以使用上面题目的套路解该题,由外向内一层一层遍历该矩阵,每次将当前层的四条边上的对应位置进行交换。例如,交换如下四个元素:
代码:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 public class RotateMatrix { public static void rotateMatrix (int [][] matrix) { if (matrix == null || matrix.length == 0 ) { return ; } int topRow = 0 ; int topCol = 0 ; int downRow = matrix.length - 1 ; int downCol = matrix[0 ].length - 1 ; while (topRow < downRow && topCol < downCol) { rotateEdge(matrix, topRow++, topCol++, downRow--, downCol--); } } public static void rotateEdge (int [][] matrix, int topRow, int topCol, int downRow, int downCol) { if (topRow > downRow || topCol > downCol) { return ; } int tmp = 0 ; int total = downCol - topCol; for (int i = 0 ; i < total; i++) { tmp = matrix[topRow][topCol + i]; matrix[topRow][topCol + i] = matrix[downRow - i][topCol]; matrix[downRow - i][topCol] = matrix[downRow][downCol - i]; matrix[downRow][downCol - i] = matrix[topRow + i][downCol]; matrix[topRow + i][downCol] = tmp; } } public static void printMatrix (int [][] matrix) { for (int i = 0 ; i != matrix.length; i++) { for (int j = 0 ; j != matrix[0 ].length; j++) { System.out.print(matrix[i][j] + " " ); } System.out.println(); } } public static void main (String[] args) { int [][] matrix = { { 1 , 2 , 3 , 4 }, { 5 , 6 , 7 , 8 }, { 9 , 10 , 11 , 12 }, { 13 , 14 , 15 , 16 } }; printMatrix(matrix); rotateMatrix02(matrix); System.out.println("=========" ); printMatrix(matrix); } }
方法二:上下翻转 + 对角翻转
使用数学规律,先将数组上下翻转,然后沿着对角线反转,同样可以得到答案。
代码:
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 26 public static void rotateMatrix02 (int [][] matrix) { if (matrix == null || matrix.length == 0 ) { return ; } int N = matrix.length; int tmp = 0 ; for (int i = 0 ; i < N / 2 ; i++) { for (int j = 0 ; j < N; j++) { tmp = matrix[i][j]; matrix[i][j] = matrix[N - 1 - i][j]; matrix[N - 1 - i][j] = tmp; } } for (int i = 0 ; i < N; i++) { for (int j = i + 1 ; j < N; j++) { tmp = matrix[i][j]; matrix[i][j] = matrix[j][i]; matrix[j][i] = tmp; } } }
zigzag 方式打印矩阵
用 zigzag 的方式打印矩阵,比如如下的矩阵
示例:
1 2 3 4 5 矩阵: 0 1 2 3 4 5 6 7 8 9 10 11 打印顺序为:0 1 4 8 5 2 3 6 9 10 7 11
思路:定义两个边界点,分别沿着下图黑色路径与灰色路径移动,二者每次都一起移动一格 。如果遇到边界就拐弯。二者每一起运动一格后,就打印二者构成的对角线上的元素(交替顺序,一次向上,一次向下),最终二者相遇在右下角时全部打印完毕。
代码:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 public class ZigZagPrintMatrix { public static void zigZagPrint (int [][] matrix) { if (matrix == null || matrix.length == 0 ) { return ; } int topRow = 0 ; int topCol = 0 ; int downRow = 0 ; int downCol = 0 ; int endRow = matrix.length - 1 ; int endCol = matrix[0 ].length - 1 ; boolean fromUp = false ; while (topRow <= endRow) { printLine(matrix, fromUp, topRow, topCol, downRow, downCol); topRow = topCol == endCol ? topRow + 1 : topRow; topCol = topCol == endCol ? topCol : topCol + 1 ; downCol = downRow == endRow ? downCol + 1 : downCol; downRow = downRow == endRow ? downRow : downRow + 1 ; fromUp = !fromUp; } } public static void printLine (int [][] matrix, boolean fromUp, int topRow, int topCol, int downRow, int downCol) { if (fromUp) { while (topRow <= downRow) { System.out.print(matrix[topRow++][topCol--] + " " ); } } else { while (topRow <= downRow) { System.out.print(matrix[downRow--][downCol++] + " " ); } } } public static void main (String[] args) { int [][] matrix = { { 1 , 2 , 3 , 4 }, { 5 , 6 , 7 , 8 }, { 9 , 10 , 11 , 12 } }; zigZagPrint(matrix); } }
KMP 算法
代码:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 public class KMP { public static int getIndexOf (String s, String m) { if (s == null || m == null || m.length() < 1 || s.length() < m.length()) { return -1 ; } char [] str1 = s.toCharArray(); char [] str2 = m.toCharArray(); int [] next = getNextArray(str2); int i1 = 0 ; int i2 = 0 ; while (i1 < str1.length && i2 < str2.length) { if (str1[i1] == str2[i2]) { i1++; i2++; } else if (next[i2] == -1 ) { i1++; } else { i2 = next[i2]; } } return i2 == str2.length ? i1 - i2 : -1 ; } public static int [] getNextArray(char [] str) { if (str.length == 1 ) { return new int []{ -1 }; } int [] next = new int [str.length]; next[0 ] = -1 ; next[1 ] = 0 ; int i = 2 ; int cn = 0 ; while (i < str.length) { if (str[cn] == str[i - 1 ]) { next[i++] = ++cn; } else if (cn > 0 ) { cn = next[cn]; } else { next[i++] = 0 ; } } return next; } }
Man
字符串常见题目
翻转单词顺序
输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. “,则输出"student. a am I”。 说明:
无空格字符构成一个单词。
输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
示例 1:
1 2 输入: "the sky is blue" 输出: "blue is sky the"
示例 2:
1 2 3 输入: " hello world! " 输出: "world! hello" 解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
示例 3:
1 2 3 输入: "a good example" 输出: "example good a" 解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
代码:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 public String reverseWords (String s) { if (s == null || s.length() < 1 ) { return s; } List<String> list = new ArrayList<>(); int left = 0 ; int right = 0 ; int count = 0 ; for (; right < s.length(); right++) { if (s.charAt(right) == ' ' ) { if (left != right) { list.add(s.substring(left, right)); count++; left = right + 1 ; } else { left++; } } } if (left != right) { list.add(s.substring(left, right)); count++; } StringBuilder sb = new StringBuilder(); while (count-- > 0 ) { String substr = list.get(count); sb.append(substr); if (count != 0 ) { sb.append(' ' ); } } return sb.toString(); } public String reverseWords (String s) { s = s.trim(); int j = s.length() - 1 , i = j; StringBuilder res = new StringBuilder(); while (i >= 0 ) { while (i >= 0 && s.charAt(i) != ' ' ) { i--; } res.append(s.substring(i + 1 , j + 1 ) + " " ); while (i >= 0 && s.charAt(i) == ' ' ) { i--; } j = i; } return res.toString().trim(); }