最小袋子数量
思路:先用暴力打表方式输出一定数量内的结果,根据结果找到规律
package com.zzf.algorithm;
/**
* @author zzf
* @date 2022-02-09
*/
public class AppleMinBags {
public static int minBags(int apple){
if(apple < 0){
return -1;
}
//优先从能装8个的袋子开始
int bag8 = apple / 8;
int rest = apple - (bag8 * 8);
while (bag8 >= 0){
if(rest % 6 == 0){
return bag8 + (rest / 6);
}
//剩余无法装完6的袋子,选择退一步
else {
bag8--;
rest += 8;
}
}
return -1;
}
public static void main(String[] args) {
for(int apple = 1; apple < 200;apple++) {
System.out.println(apple + " : "+ minBags(apple));
}
}
}
发现的规律是从18开始具有明显的分组倾向,每8个一组,而且其中奇数返回结果是-1,其余结果是当前组数+3,18以内的单独处理
package com.zzf.algorithm;
/**
* @author zzf
* @date 2022-02-09
*/
public class AppleMinBags {
public static int minBags(int apple){
//奇数返回-1
if((apple & 1) !=0){
return -1;
}
if(apple < 18){
return apple == 0 ? 0 :(apple == 6 || apple == 8) ? 1
: (apple == 12 || apple == 14 || apple == 16) ? 2 : -1;
}
return (apple - 18) / 8 + 3;
}
public static void main(String[] args) {
for(int apple = 1; apple < 200;apple++) {
System.out.println(apple + " : "+ minBags(apple));
}
}
}
连续整数和的数
思路:根据暴力大表输出判断200以内的数字是否为连续正数和的数,尝试找出规律,然后再利用规律写出更优的代码
package com.zzf.algorithm;
/**
* @author zzf
* @date 2022-02-09
*/
public class MSumToN {
public static boolean isMSum(int num){
for (int i = 1; i <= num; i++) {
int sum = i;
for (int j = i + 1; j <= num; j++) {
if(sum + j > num){
break;
}
if(sum + j == num){
return true;
}
sum += j;
}
}
return false;
}
public static void main(String[] args) {
for (int num = 1; num < 200; num++) {
System.out.println(num + " : " + isMSum(num));
}
}
}
部分结果
根据结果可以发现凡是2的幂次方的数字都不满足条件,因此根据这一规律可以得到更优的代码
package com.zzf.algorithm;
/**
* @author zzf
* @date 2022-02-09
*/
public class MSumToN {
public static boolean isMSum(int num){
/*
num & (num - 1)是判断是否为2的幂次方的位运算操作
因为num如果是2的幂次方,二进制数中只有1个1
num-1会把后面的几位反转,&操作得到的会是0
*/
return (num & (num - 1)) != 0;
}
public static void main(String[] args) {
for (int num = 1; num < 200; num++) {
System.out.println(num + " : " + isMSum(num));
}
}
}
打印之字形矩阵
准备指向左上角开始位置的A点和B点,确定行列边界条件,A点先向右移动一步,B点就向下移动一步,每次AB形成一条斜线,A直到不能向右,就往下,B直到不能向下就向右,最后控制A,B一个不越界就行,加一个控制打印方向的变量,每次AB形成斜线时更新变量,就能做到之字形打印
package com.zzf.algorithm;
/**
* @author zzf
* @date 2022-02-09
*/
public class ZigZagPrintMatrix {
public static void printMatrixZigZag(int[][] matrix){
int AR = 0;
int AC = 0;
int BR = 0;
int BC = 0;
int endR = matrix.length - 1;
int endC = matrix[0].length - 1;
boolean fromUp = false;
while(AR != endR +1){
//打印
printLevel(matrix,AR,AC,BR,BC,fromUp);
//统一动的放后
//A向右移动直到最后一列就向下
AR = AC == endC ? AR + 1 : AR;
AC = AC == endC ? AC : AC + 1;
//B向下移动直到最后一行就向右
BC = BR == endR ? BC + 1 : BC;
BR = BR == endR ? BR : BR + 1;
fromUp = !fromUp;
}
System.out.println();
}
public static void printLevel(int[][] m,int AR,int AC,int BR,int BC,boolean f){
//从上往下打印
if(f){
while (AR != BR + 1){
System.out.print(m[AR++][AC--] + " ");
}
}
//从下往上打印
else{
while (BR != AR - 1){
System.out.print(m[BR--][BC++] + " ");
}
}
}
public static void main(String[] args) {
int[][] matrix = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } };
printMatrixZigZag(matrix);
}
}
转圈打印矩阵
思路:准备标记左上角行列和右下角行列的变量,每次打印一条边,从最上条边开始,先向右打印,直到遇到右上角,就向下打印,直到遇到右下角,就向左打印,直到遇到左上角,要注意只有一行或只有一列的特殊情况,按圈打印,由外到内
package com.zzf.algorithm;
/**
* @author zzf
* @date 2022-02-09
*/
public class PrintMatrixSpiralOrder {
public static void spiralOrderPrint(int[][] matrix){
int tR = 0;
int tC = 0;
int dR = matrix.length - 1;
int dC = matrix[0].length - 1;
while (tR <= dR && tC <= dC){
printEdge(matrix,tR++,tC++,dR--,dC--);
}
}
/**
*
* @param m
* @param tR:左上角行
* @param tC:左上角列
* @param dR:右下角行
* @param dC:右下角列
*/
public static void printEdge(int[][] m,int tR,int tC,int dR,int dC){
if(tR == dR){ //只有一行的情况
for (int i = tC; i <= dC; i++) {
System.out.print(m[tR][i] + " ");
}
}
else if(tC == dC){ //只有一列的情况
for (int i = tR; i <= dR; i++) {
System.out.print(m[i][tC] + " ");
}
}else {
//当前列和当前行
int curC = tC;
int curR = tR;
while(curC != dC){
System.out.print(m[curR][curC] + " ");
curC++;
}
while (curR != dR){
System.out.print(m[curR][curC] + " ");
curR++;
}
while (curC != tC){
System.out.print(m[curR][curC] + " ");
curC--;
}
while (curR != tR){
System.out.print(m[curR][curC] + " ");
curR--;
}
}
}
public static void main(String[] args) {
int[][] matrix = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 },
{ 13, 14, 15, 16 } };
spiralOrderPrint(matrix);
}
}
顺时针原地旋转正方形矩阵90度
思路:按圈处理,从外到内旋转,把一圈的左上角,右上角,右下角,左下角归为4个小组,而且是依次作为一条边起始,旋转就是依次交换这几个位置,而且通过观察,一条边上,以最上面的边的小组为例,要交换的个数=右上角列位置-左上角列位置-1,减1是不包括右上角位置,旋转完一圈后整体缩小到内一圈,一直循环下去,直到把整个正方形矩阵旋转完毕
package com.zzf.algorithm;
/**
* @author zzf
* @date 2022-02-09
*/
public class RotateMatrix {
public static void rotate(int[][] matrix){
int a = 0;
int b = 0;
int c = matrix.length - 1;
int d = matrix[0].length - 1;
while(a < c){
rotateEdge(matrix,a++,b++,c--,d--);
}
}
public static void rotateEdge(int[][] m,int a,int b,int c,int d){
int tmp = 0;
for(int i = 0; i< d - b; i++){
tmp = m[a][b+i];
//左下角到左上角
m[a][b+i] = m[c - i][b];
//右下角到左下角
m[c - i][b] = m[c][d - i];
//右上角到右下角
m[c][d - i] = m[a + i][d];
//左上角到右上角
m[a + i][d] = 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);
rotate(matrix);
System.out.println("=========");
printMatrix(matrix);
}
}