- 大妈一开始手上有x个鸡蛋,她想让手上的鸡蛋数量变成y,
操作1 : 从仓库里拿出1个鸡蛋到手上,x变成x+1个,
操作2 : 如果手上的鸡蛋数量是3的整数倍,大妈可以直接把三分之二的鸡蛋放回仓库,手里留下三分之一。
返回从x到y的最小操作次数。
1 <= x,y <= 10^18。
————————————————
版权声明:本文为CSDN博主「福大大架构师每日一题」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_48502062/article/details/125155668
/**
* 求解x->y最少的次数
* @param x
* @param y
* @return
*/
public static int minTime(int x,int y){
if (x<=y){
return y-x;
}
int mod = x%3;
//要凑齐到3的倍数要花费的行动点数
int need = mod ==0?0:(mod==1?2:1);
//每次都尽可能的增加现有最大的鸡蛋数量
return need+1+minTime((x+2)/3,y);
}
/**
* 优化方案
* @param x
* @param y
* @return
*/
public static int minTimePlus(int x,int y){
if (x<=y){
return y-x;
}
//这个限制目前认为最好的
int limit = minTime(x,y);
//新建一个dp数组来进行存储递归过程中出现的次数
int[][] dp = new int[x+1+limit][limit+1];
return process(x,y,0,limit,dp);
}
/**
*
* @param cur 当前的鸡蛋数量
* @param aim 目标的鸡蛋数量
* @param pre 之前已经用了多少行动点数
* @param limit 一定的行动数,超过就放弃
* @param dp dp数组
* @return
*/
private static int process(int cur, int aim, int pre, int limit, int[][] dp) {
if (pre>limit){
return Integer.MAX_VALUE;
}
if (dp[cur][pre] !=0){
return dp[cur][pre];
}
int ans = 0;
if (cur==aim){
return pre;
}else {
int p1 = process(cur+1,aim,pre+1,limit,dp);
int p2 = Integer.MAX_VALUE;
if (cur%3==0){
p2 = process(cur/3,aim,pre+1,limit,dp);
}
ans = Math.min(p1,p2);
}
//往回进行更新
dp[cur][pre] = ans;
return ans;
}