丢棋子问题

丢棋子

题目

一座大楼有\(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层

解题思路

(1)丢棋子

感觉这篇博客写的很好,记录一下。
使用到了滚动数组的方法,正常从左边开始访问:

\[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;
    }
}
posted @ 2022-04-06 15:25  LibraXiong  阅读(116)  评论(0)    收藏  举报