打表技巧和矩阵处理技巧(Java)


一、打表法

  1. 问题如果返回值不多,可以用hardcode的方式列出,作为程序的一部分
  2. 一个问题解决时底层频繁使用规模不大的小问题的解,如果小问题的返回值满足条件1),可以把小问题列出一张表,作为程序的一部分
  3. 打表找规律

打表找规律
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));
		}
	}
	
}

运行结果
在这里插入图片描述

二、矩阵处理技巧

  1. zigzag打印矩阵
  2. 转圈打印矩阵
  3. 原地旋转正方形矩阵
    核心技巧: 找到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();
	}
	
}

运行结果
在这里插入图片描述


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值