一座大楼有 n+1 层,地面算作第0层,最高的一层为第 n 层。已知棋子从第0层掉落肯定不会摔碎,从第 i 层掉落可能会摔碎,也可能不会摔碎。
给定整数 n 作为楼层数,再给定整数 k 作为棋子数,返回如果想找到棋子不会摔碎的最高层数,即使在最差的情况下扔的最小次数。一次只能扔一个棋子。
数据范围:
要求:空间复杂度 ,时间复杂度 (m是最终返回的结果)
10,1
10
因为只有1棵棋子,所以不得不从第1层开始一直试到第10层,在最差的情况下,即第10层是不会摔坏的最高层,最少也要扔10次
3,2
2
先在2层扔1棵棋子,如果碎了,试第1层,如果没碎,试第3层
105,2
14
第一个棋子先在14层扔,碎了则用仅存的一个棋子试1~13层
若没碎,第一个棋子继续在27层扔,碎了则用仅存的一个棋子试15~26层
若没碎,第一个棋子继续在39层扔,碎了则用仅存的一个棋子试28~38层
若没碎,第一个棋子继续在50层扔,碎了则用仅存的一个棋子试40~49层
若没碎,第一个棋子继续在60层扔,碎了则用仅存的一个棋子试51~59层
若没碎,第一个棋子继续在69层扔,碎了则用仅存的一个棋子试61~68层
若没碎,第一个棋子继续在77层扔,碎了则用仅存的一个棋子试70~76层
若没碎,第一个棋子继续在84层扔,碎了则用仅存的一个棋子试78~83层
若没碎,第一个棋子继续在90层扔,碎了则用仅存的一个棋子试85~89层
若没碎,第一个棋子继续在95层扔,碎了则用仅存的一个棋子试91~94层
若没碎,第一个棋子继续在99层扔,碎了则用仅存的一个棋子试96~98层
若没碎,第一个棋子继续在102层扔,碎了则用仅存的一个棋子试100、101层
若没碎,第一个棋子继续在104层扔,碎了则用仅存的一个棋子试103层
若没碎,第一个棋子继续在105层扔,若到这一步还没碎,那么105便是结果
public int solve (int n, int k) { return bestWay(n,k); // write code here } public static int bestWay(int remain,int k){//最吊的方法 int[] dp = new int[k + 1]; int step = 1; while(true){ for(int i = k;i > 0;i--){ dp[i] = dp[i-1] + dp[i] + 1; } if(dp[k] >= remain){ return step; } step++; } }令人自豪四边形不等式:
public int dpWay(int n,int sum){//四边形不等式 int[][] dp = new int[n+1][sum+1]; int[][] s = new int[n+1][sum+1]; for(int i = 0;i < dp.length;i++){ s[i][1] = 1; dp[i][1] = i; } for(int i = 1;i < dp[0].length;i++){ dp[1][i] = 1; s[1][i] = 1; } for(int i = 2;i < dp.length;i++){ for(int j = sum;j >= 2;j--){ int low = s[i-1][j]; int up = j < sum ? s[i][j+1] : i; dp[i][j] = i; s[i][j] = i; for(int k = low;k <= up;k++){ int max = Math.max(dp[k-1][j-1],dp[i-k][j]) + 1; if(max < dp[i][j]){ dp[i][j] = max; s[i][j] = k; } } } } return dp[n][sum]; }
import java.util.*; public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * 返回最差情况下扔棋子的最小次数 * @param n int整型 楼层数 * @param k int整型 棋子数 * @return int整型 */ public int solve (int n, int k) { // write code here /******************************************************************************************************/ // 最原始的方法(最好理解) /* int[][] dp = new int[k + 1][n + 1]; for (int j = 1; j <= n; j++) { dp[1][j] = j; } for (int i = 2; i <= k; i++) { for (int j = 1; j <= n; j++) { dp[i][j] = j; for (int x = 1; x <= j; x++) { dp[i][j] = Math.min(Math.max(dp[i - 1][x - 1], dp[i][j - x]) + 1, dp[i][j]); } } } return dp[k][n]; */ /******************************************************************************************************/ // 使用二分查找 /* int[][] dp = new int[k + 1][n + 1]; for (int j = 1; j <= n; j++) { dp[1][j] = j; } for (int i = 2; i <= k; i++) { for (int j = 1; j <= n; j++) { dp[i][j] = j; int l = 1; int r = j; int mid; while (l < r) { mid = l + ((r - l) >> 1); if (dp[i - 1][mid - 1] < dp[i][j - mid]) { l = mid + 1; } else { r = mid; } } dp[i][j] = Math.min(Math.max(dp[i - 1][l - 1], dp[i][j - l]) + 1, dp[i][j]); } } return dp[k][n]; */ /******************************************************************************************************/ // 楼层高肯定比楼层低所需要的查找次数要多 /* int[][] dp = new int[k + 1][n + 1]; for (int j = 1; j <= n; j++) { dp[1][j] = j; } for (int i = 2; i <= k; i++) { int x = 1; for (int j = 1; j <= n; j++) { dp[i][j] = j; while (dp[i - 1][x - 1] < dp[i][j - x]) { x++; } dp[i][j] = Math.min(Math.max(dp[i - 1][x - 1], dp[i][j - x]) + 1, dp[i][j]); } } return dp[k][n]; */ /******************************************************************************************************/ // 使用滚动数组的方式,优化存储空间 int[][] dp = new int[2][n + 1]; for (int j = 1; j <= n; j++) { dp[1][j] = j; } int cur; int pre; for (int i = 2; i <= k; i++) { int x = 1; cur = i % 2; pre = i % 2 == 0 ? 1 : 0; for (int j = 1; j <= n; j++) { dp[cur][j] = j; while (dp[pre][x - 1] < dp[cur][j - x]) { x++; } dp[cur][j] = Math.min(Math.max(dp[pre][x - 1], dp[cur][j - x]) + 1, dp[cur][j]); } } return dp[k % 2][n]; } }
import java.util.*; public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * 返回最差情况下扔棋子的最小次数 * @param n int整型 楼层数 * @param k int整型 棋子数 * @return int整型 */ public int solve (int n, int k) { // 状态转移方程:dp[i][j]=dp[i][j-1]+dp[i-1][j-1]+1 if(k==1) return n; int h=(int)(Math.log(n)/Math.log(2))+1; if(k>h) return h; int[] dp=new int[k]; int i=1; while(true){ int p=0; for(int j=0;j<k;j++){ int temp=dp[j]; dp[j]+=p+1; p=temp; if(dp[j]>=n) return i; } i++; } } }