丢棋子问题
丢棋子
题目
一座大楼有\(0 \sim N0∼N\)层,地面算作第\(0\)层,最高的一层为第\(N\)层。已知棋子从第\(0\)层掉落肯定不会摔碎,从第i层掉落可能会摔碎,也可能不会摔碎(\(1 \leqslant i \leqslant N1⩽i⩽N\))。给定整数\(N\)作为楼层数,再给定整数\(K\)作为棋子数,返回如果想找到棋子不会摔碎的最高层数,即使在最差的情况下扔的最小次数。一次只能扔一个棋子。
[要求] 时间复杂度在最坏情况下为\(O(n)\)
输入示例
输入: 3 2
输出: 2
解释: 先在2层扔1棵棋子,如果碎了,试第1层,如果没碎,试第3层
解题思路
感觉这篇博客写的很好,记录一下。
使用到了滚动数组的方法,正常从左边开始访问:
\[dp[j]\Rightarrow dp[i-1][j] \tag{1}
\]
\[ dp[j-1]\Rightarrow dp[i][j-1] \tag{2}
\]
而从右边开始访问:
\[dp[j]\Rightarrow dp[i-1][j] \tag{3}
\]
\[dp[j-1]\Rightarrow dp[i-1][j-1] \tag{4}
\]
代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Scanner;
import java.util.*;
public class Main{
public static BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
public static void main(String[] args) throws IOException{
String[] N_K=br.readLine().split(" ");
int N=Integer.parseInt(N_K[0]);
int K=Integer.parseInt(N_K[1]);
System.out.println(helper(N,K));
}
public static int helper(int N,int K) {
int best=log2(N);
if(K>=best) return best;
int[] dp=new int[K+1];
int res=0;
while(true)
{
res++;
for(int j=K;j>=1;j--) // 逆序能更好取到dp[i-1][j-1];
{
dp[j]=dp[j]+dp[j-1]+1;
if(dp[j]>=N) return res;
}
}
}
public static int log2(int N) {
//二分是最快的 如果棋子数量大于等于 log2N + 1 直接返回
int res=0; //求二进制位数 其实也可以把这个过程想成一棵树高
while(N>0)
{
res++;
N>>=1;
}
return res;
}
}

浙公网安备 33010602011771号