一、打表法
当一个题目输入时是int, 输出时是int型或boolean型,4成以上可以采用打表法
先用傻代码得到规律,根据规律写出优化代码
题目一
小虎去附近的商店买苹果,奸诈的商贩使用了捆绑交易,只提供6个每袋和8个 每袋的包装包装不可拆分。可是小虎现在只想购买恰好n个苹果,小虎想购买尽 量少的袋数方便携带。如果不能购买恰好n个苹果,小虎将不会购买。输入一个 整数n,表示小虎想购买的个苹果,返回最小使用多少袋子。如果无论如何都不 能正好装下,返回-1。
普通代码
打表法代码
题目二
牛牛和羊羊都很喜欢青草。今天他们决定玩青草游戏。 最初有一个装有n份青草的箱子,牛牛和羊羊依次进行,牛牛先开始。在每个回合中,每个 玩家必须吃一些箱子中的青草,所吃的青草份数必须是4的x次幂,比如1,4,16,64等等。 不能在箱子中吃到有效份数青草的玩家落败。假定牛牛和羊羊都是按照最佳方法进行游 戏,请输出胜利者的名字。
普通代码
public static String winner1(int n){
//依次让先手牛先吃1分,4分。。。如果出现可以赢的情况,就是赢家是先手牛
int base = 1;//先手牛先吃的草
while (base <= n){
//当前一共有n份草,先手吃掉的是base份,n - base 是留给后手的草
//如果n - base是后手赢了,也就是算上base份草的时候是先手赢了
if (winner1(n - base).equals("后手")){
return "先手";
}
if (base > n / 4){
break;//为了防止溢出
//注意不可以写成(base * 4 > n)因为你在算(base * 4)的时候就已经溢出了
}
base *= 4;
}
return "后手";//所有的都尝试过了,没有返回先手赢就只能后手赢了
}
public static void main(String[] args) {
System.out.println(winner1(0));
}
打表法代码
public static String winner2(int n){
if (n % 5 == 0 || n % 5 == 2){
return "后手";
}else {
return "先手";
}
}
二、预处理法
题目一
牛牛有一些排成一行的正方形。每个正方形已经被染成红色或者绿色。牛牛现在可 以选择任意一个正方形然后用这两种颜色的任意一种进行染色,这个正方形的颜色将 会被覆盖。牛牛的目标是在完成染色之后,每个红色R都比每个绿色G距离最左侧近。 牛牛想知道他最少需要涂染几个正方形。 如样例所示: s = RGRGR 我们涂染之后变成RRRGG满足要求了,涂染的个数为2,没有比这个更好的涂染方案。
预处理法代码
统计 i ~ N - 1 上的R的数量,以便知道后面直接涂成G的时候的个数 统计 0 ~ i 上的G的数量,以便知道前面直接涂成R的时候的个数 以便可以及时的取出,不需要重复的计算
// RGRGR -> RRRGG
public static int minPaint(String s) {
if (s == null || s.length() < 2) {
return 0;
}
char[] chs = s.toCharArray();
int[] right = new int[chs.length];
//统计 i ~ N - 1上的R的数量,以便知道后面直接涂成G的时候的个数
right[chs.length - 1] = chs[chs.length - 1] == 'R' ? 1 : 0;
for (int i = chs.length - 2; i >= 0; i--) {
right[i] = right[i + 1] + (chs[i] == 'R' ? 1 : 0);
}
//假设min的最大值是number[0],也就是全变成G的数量
int res = right[0];
int left = 0;
for (int i = 0; i < chs.length - 1; i++) {
left += chs[i] == 'G' ? 1 : 0;
//left 存的是0 ~ i上G的数量
res = Math.min(res, left + right[i + 1]);
}
res = Math.min(res, left + (chs[chs.length - 1] == 'G' ? 1 : 0));
return res;
}
public static void main(String[] args) {
String test = "GGGGGR";
System.out.println(minPaint(test));
}
题目二
给定一个N * N的矩阵matrix,只有0和1两种值,返回边框全是1的最大正方形的边 长长度。 例如:
01111
01001
01001
01111
01011 其中边框全是1的最大正方形的大小为4 * 4,所以返回4。
普通法
预处理方法代码
可以优化最后一步是不是上面的值都是1,建立两个矩阵,一个存当前点右方有多少个连续的1,一个存当前点下方有多少个连续的1。
这个和简单代码的思路是不同的,这个更加的简洁,先从最长的长度开始找,看有没有符合条件的。
public static void setBorderMap(int[][] m, int[][] right, int[][] down) {
int r = m.length;
int c = m[0].length;
//前面的处理都是为了下面循环的时候,不会越界
if (m[r - 1][c - 1] == 1) {
right[r - 1][c - 1] = 1;
down[r - 1][c - 1] = 1;
}
for (int i = r - 2; i != -1; i--) {
if (m[i][c - 1] == 1) {
right[i][c - 1] = 1;
down[i][c - 1] = down[i + 1][c - 1] + 1;
}
}
for (int i = c - 2; i != -1; i--) {
if (m[r - 1][i] == 1) {
right[r - 1][i] = right[r - 1][i + 1] + 1;
down[r - 1][i] = 1;
}
}
for (int i = r - 2; i != -1; i--) {
for (int j = c - 2; j != -1; j--) {
if (m[i][j] == 1) {
right[i][j] = right[i][j + 1] + 1;
down[i][j] = down[i + 1][j] + 1;
}
}
}
}
public static int getMaxSize(int[][] m) {
int[][] right = new int[m.length][m[0].length];
int[][] down = new int[m.length][m[0].length];
setBorderMap(m, right, down);
//先从最长的长度开始找,看有没有符合条件的
//这个和简单代码的思路是不同的,这个更加的简洁
for (int size = Math.min(m.length, m[0].length); size != 0; size--) {
if (hasSizeOfBorder(size, right, down)) {
return size;
}
}
return 0;
}
public static boolean hasSizeOfBorder(int size, int[][] right, int[][] down) {
for (int i = 0; i != right.length - size + 1; i++) {
for (int j = 0; j != right[0].length - size + 1; j++) {
if (right[i][j] >= size && down[i][j] >= size
&& right[i + size - 1][j] >= size
&& down[i][j + size - 1] >= size) {
return true;
}
}
}
return false;
}
public static int[][] generateRandom01Matrix(int rowSize, int colSize) {
int[][] res = new int[rowSize][colSize];
for (int i = 0; i != rowSize; i++) {
for (int j = 0; j != colSize; j++) {
res[i][j] = (int) (Math.random() * 2);
}
}
return res;
}
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 = generateRandom01Matrix(7, 8);
printMatrix(matrix);
System.out.println(getMaxSize(matrix));
}
题目三
给定一个函数f,可以1~5的数字等概率返回一个。请加工出1~7的数字等概率 返回一个的函数g。
预处理法代码
public static int f(){
return (int) (Math.random() * 5) + 1;
}
// 等概率返回0和1的函数
public static int r01(){
int res = 0;
do {
res = f();
//如果扔出3就重新仍
}while (res == 3);
return res < 3 ? 0 : 1;
}
public static int g(){ //等概率1 ~ 7
int res = 0;
do {
res = (r01() << 2) + (r01() << 1) + r01();
//保证等概率0 ~ 6 仍出7就重新仍
}while (res == 7);
return res + 1;
}
题目四
给定一个非负整数n,代表二叉树的节点个数。返回能形成多少种不同的二叉树结构
预处理法代码
public static int process(int n){
if (n < 0){
return 0;
}
if (n == 0){
return 1;
}
if (n == 2){
return 2;
}
int res = 0;
for (int leftNum = 0; leftNum <= n - 1; leftNum++){
int leftWays = process(leftNum);
int rightWays = process(n - 1 - leftNum);
res += leftWays * rightWays;
}
return res;
}