一、打表法
- 问题如果返回值不多,可以用hardcode的方式列出,作为程序的一部分
- 一个问题解决时底层频繁使用规模不大的小问题的解,如果小问题的返回值满足条件1),可以把小问题列出一张表,作为程序的一部分
- 打表找规律
打表找规律
1) 某面试题, 输入参数类型简单,并且只有一个实际参数
2) 要求的返回值类型也简单,并且只有一个
3) 用暴力方法,把输入参数对应的返回值打印出来看看,优化code
1. 小虎买苹果
题目
先暴力解在找出规律,优化算法。
package TableAndMatrix;
public class BuyApple {
public static int buyApple1(int n) { //暴力法找规律
if((n & 1) == 1) return -1; // 奇数一定不能装
int n_eight = n / 8; //找到最大使用的8号袋子的数量
while(n - n_eight * 8 < 24) { //如果剩余苹果大于24,那么剩下的苹果想要用最少的袋子这24个就必须用8号袋子装(24 / 8 = 3 24 / 6 = 4),而减掉24后剩余的苹果会陷入循环。
if((n - n_eight * 8) % 6 == 0) {
return n_eight + ((n - n_eight * 8) / 6);
}
--n_eight; // 减少用8号袋子的量
if(n_eight < 0) break; // 所有情况均考虑完扔未找到
}
return -1;
}
public static int buyApple2(int n) { //找到规律版
if((n & 1) == 1) return -1;
if(n == 0) return 0;
if(n == 6 || n == 8) return 1;
if(n == 12 || n == 14 || n == 16) return 2;
if(n >= 18) {
return (n - 18) / 8 + 3;
}
return -1;
}
public static void main(String[] args) {
for(int i=0; i<100; ++i) {
System.out.print(i+":" + buyApple1(i) + " ");
}
System.out.println();
for(int i=0; i<100; ++i) {
System.out.print(i+":" + buyApple2(i) + " ");
}
}
}
运行结果
2. 牛羊轮流吃草
题目
package TableAndMatrix;
public class EatGrass {
public static String eatGrass1(int n) { //暴力方法
//0:后手 1:先手 2:后手 3:先手 4:先手 5:先手
if(n < 5) {
return (n == 0 || n == 2) ? "后手": "先手";
}
int amount = 1;
int limit = n >> 2; //防止溢出
while(amount <= n ) {
String ans = eatGrass1(n - amount);
if(ans.equals("后手")) {
return "先手";
}
if(amount > limit) break;
amount <<= 2; //乘4
}
return "后手";
}
public static String eatGrass2(int n) { //打表
return (n % 5 == 0 || n == 2)? "后手": "先手";
}
public static void main(String[] args) {
for(int i=0; i<50; ++i) {
System.out.print(i + ":" + eatGrass1(i)+"赢 ");
System.out.println(i + ":" + eatGrass1(i)+"赢 ");
}
}
}
3.连续整数和
题目
package TableAndMatrix;
public class AddNum {
public static boolean addNum1(int n) { //暴力法
for(int i=1; i<n; ++i) {
int sum = 0;
int j = i;
while(sum < n) {
sum += j;
++j;
if(sum == n) {
return true;
}
}
}
return false;
}
public static boolean addNum2(int n) {
if((n & (n - 1) )==0) return false; //如果是2的次方数,则返回false
else return true;
}
public static void main(String[] args) {
for(int i=1; i<100; ++i) {
System.out.println(i+":\t"+addNum1(i) + "\t" + addNum2(i));
}
}
}
运行结果
二、矩阵处理技巧
- zigzag打印矩阵
- 转圈打印矩阵
- 原地旋转正方形矩阵
核心技巧: 找到coding上的宏观调度
1.zigzag打印矩阵
找到每一轮的斜线
package TableAndMatrix;
public class Zigzag {
public static int[][] matrix;
static {
int m = 10;
int n = 5;
matrix = new int [m][n];
int i = 0;
for(int j=0; j< m; j++) {
for(int k=0; k<n; ++k) {
matrix[j][k] = i;
System.out.print(i+(i <= 9? " ":" "));
++i;
}
System.out.println();
}
}
public static void printZigzag() {
//A ,B唯一确定一条斜线
int[] A = new int[]{0, 0};
int[] B = new int[]{0, 0};
// up标志从上往下打印这条斜线还是从下向上打
boolean up = true; //向上打印
int row_max = matrix.length - 1;
int column_max = matrix[0].length - 1;
for(int i = 0; i < row_max + column_max + 1; ++i) {
printLine(A, B, up);
B[1] = B[0] == row_max? B[1] + 1: B[1];
B[0] = B[0] == row_max? B[0]: B[0] + 1;
A[0] = A[1] == column_max? A[0] + 1: A[0];
A[1] = A[1] == column_max? A[1]: A[1] + 1;
up = !up; //转向
}
}
public static void printLine(int[] A, int[] B, boolean up) {
if(up) {
int[] start = new int[] {B[0], B[1]};
while(start[0] != A[0] || start[1] != A[1]) {
System.out.print(matrix[start[0]][start[1]] + (matrix[start[0]][start[1]] <= 9? " ": " "));
start[0] -= 1;
start[1] += 1;
}
System.out.print(matrix[start[0]][start[1]] + (matrix[start[0]][start[1]] <= 9? " ": " "));
}else {
int[] start = new int[] {A[0], A[1]};
while(start[0] != B[0] || start[1] != B[1]) {
System.out.print(matrix[start[0]][start[1]] + (matrix[start[0]][start[1]] <= 9? " ": " "));
start[0] += 1;
start[1] -= 1;
}
System.out.print(matrix[start[0]][start[1]] + (matrix[start[0]][start[1]] <= 9? " ": " "));
}
System.out.println();
}
public static void main(String[] args) {
printZigzag();
}
}
运行结果
2.转圈打印矩阵
确定边界,确定每一层
package TableAndMatrix;
public class Rotate {
public static int[][] matrix;
static {
int m = 10;
int n = 6;
matrix = new int [m][n];
int i = 0;
for(int j=0; j< m; j++) {
for(int k=0; k<n; ++k) {
matrix[j][k] = i;
System.out.print(i+(i <= 9? " ":" "));
++i;
}
System.out.println();
}
}
public static void rotatePrint() {
//A, B确定层的左上角与右下角
int[] A = new int[] {0, 0};
int[] B = new int[] {matrix.length - 1, matrix[0].length - 1};
while(A[0] <= B[0] && A[1] <= B[1]) {
if(A[0] == B[0]) { //剩余一行
for(int i = A[1]; i<B[1]; ++i) {
System.out.print(matrix[A[0]][i] + " ");
}
}else if(A[1] == B[1]) { //剩余一列
for(int i = A[0]; i<B[0]; ++i) {
System.out.print(matrix[i][A[1]] + " ");
}
}else { //构成一圈
int[] start = new int[] {A[0], A[1]};
while(start[1] < B[1]) {
System.out.print(matrix[start[0]][start[1]] + " "); //向右走
++start[1];
}
while(start[0] < B[0]) {
System.out.print(matrix[start[0]][start[1]] + " ");//向下走
++start[0];
}
while(start[1] > 0) {
System.out.print(matrix[start[0]][start[1]] + " ");//向左走
--start[1];
}
while(start[0] > 0) {
System.out.print(matrix[start[0]][start[1]] + " ");//向上走
--start[0];
}
}
System.out.println();
++A[1];
++A[0];
--B[0];
--B[1];
}
}
public static void main(String[] args) {
System.out.println();
rotatePrint();
}
}
运行结果
3.原地旋转正方形矩阵(旋转90°)
分组分层进行调整旋转
package TableAndMatrix;
public class Rotate {
public static int[][] matrix;
static {
int m = 10;
matrix = new int [m][m];
int i = 0;
for(int j=0; j< m; j++) {
for(int k=0; k<m; ++k) {
matrix[j][k] = i;
System.out.print(i+(i <= 9? " ":" "));
++i;
}
System.out.println();
}
}
public static void rotate() {
//分圈分组打印,用A和B标记哪一圈 A为左上角B为右下角
int A = 0; //x,y坐标相同就不再重复存储了
int B = matrix.length - 1;
while(A < B) {
int start = A;
while(start < B) { //每组四个值
int temp = matrix[A][start];
matrix[A][start] = matrix[B - start + A][A];
matrix[B - start + A][A] = matrix[B][B - start + A];
matrix[B][B - start + A] = matrix[start][B];
matrix[start][B] = temp;
start++;
}
++A;
--B;
}
System.out.println();
int m = matrix.length;
for(int j=0; j< m; j++) {
for(int k=0; k<m; ++k) {
System.out.print(matrix[j][k] + (matrix[j][k] <= 9? " ": " "));
}
System.out.println();
}
}
public static void main(String[] args) {
rotate();
}
}
运行结果