有假币
题目描述:
居然有假币!
现在猪肉涨了,但是农民的工资却不见涨啊,没钱怎么买猪肉啊。nowcoder这就去买猪肉,结果找来的零钱中有假币!!!可惜nowcoder
一不小心把它混进了一堆真币里面去了。只知道假币的重量比真币的质量要轻,给你一个天平(天平两端能容纳无限个硬币),请用最快的时间把那个可恶的假币找出来。输入描述: 1≤n≤2^30,输入0结束程序。
输出描述: 最多要称几次一定能把那个假币找出来?
题解:
要找到一堆货币中的假币,最快的方式是分3堆,使用其中两堆称重即可:
假币比真币轻,所以:
(1) 如果A<B,那么假币在A
(2)如果A>B,那么假币在B
(3) 如果A=B,那么假币在C
以上将一堆货币分为三份,是最快找到假币的方式
题目问最多需要称几次,那么最坏的情况就是假币每次都在三份最多的那份里边
对于n个货币,n的范围为[1,2^30],每次分三份,找最多的那份,即为n/3向上取整。
如n=4,则分为1, 1, 2,取最多的2 n=5,则分为2,2,1,取最多的2 .
解题思路:
以上需要解决n/3向上取整的问题
可以使用Math.ceil()方法
需要注意,n/3 是int/ int,返回值也是int,小数已经丢失了
应该使用: (double)n/3 返回-个浮点数,再作为参数传入Math.ceil()方法
即: Math.cil(double)n/3)
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner scan=new Scanner(System.in);
while(scan.hasNext()){
int n=scan.nextInt();
if(n==0) break;
int count=0;
while(n>=2){
n=(int)Math.ceil((double)n/3);
count++;
}
System.out.println(count);
}
}
}
求正数数组的最小不可组成和
给定一个全是正数的数组arr,定义一下arr的最小不可组成和的概念:
1,arr的所有非空子集中,把每个子集内的所有元素加起来会出现很多的值,其中最小的记为min,最大的记为max;
2,在区间[min,max]上,如果有一些正数不可以被arr某一个子集相加得到,那么这些正数中最小的那个,就是arr的最小不可组成和;
3,在区间[min,max]上,如果所有的数都可以被arr的某一个子集相加得到,那么max+1是arr的最小不可组成和;
举例: arr = {3,2,5} arr的min为2,max为10,在区间[2,10]上,4是不能被任何一个子集相加得到的值中最小的,所以4是arr的最小不可组成和; arr = {3,2,4} arr的min为2,max为9,在区间[2,9]上,8是不能被任何一个子集相加得到的值中最小的,所以8是arr的最小不可组成和; arr = {3,1,2} arr的min为1,max为6,在区间[2,6]上,任何数都可以被某一个子集相加得到,所以7是arr的最小不可组成和;
请写函数返回arr的最小不可组成和。
题解:
要满足子集和为j, arr 数组中每个元素只有一种可能,包含在其中子集中,或不包含:
如果arr[0] - arr[i]有子集和j,如果arr[i]在某个子集中,那么可以推出以下结论:
数组arr中,对非arr[i]的其他元素所组成的子集进行求和,- -定存在j-arr[i]这个子集和
解题思路:
先把能满足的子集和找到: arr[i]=j
再递推:如果f(j-arr[i])= true,那么对arr[i]元素来说,满足f(j)= true
对于题解来说,可以让arr[i]=j时,也满足f(j-arr[i]) = true,即f(0)=true
每次只是更新f(j)的值即可。如果f(j)=true,不需要更新,如果为false,更新为f(j-arr[i]) 的值
public class Solution {
/**
* 正数数组中的最小不可组成和
* 输入:正数数组arr
* 返回:正数数组中的最小不可组成和
*/
public int getFirstUnFormedNum(int[] arr) {
int min=Integer.MAX_VALUE;
int max=0;
for(int i=0;i<arr.length;i++){
max+=arr[i];
min=Math.min(min,arr[i]);
}
boolean[] result=new boolean[max+1];
result[0]=true;
for(int i=0;i<arr.length;i++){
for(int j=max;j>=arr[i];j--){
result[j]=result[j-arr[i]] || result[j];
}
}
for(int i=min;i<result.length;i++){
if(!result[i])
return i;
}
return max+1;
}
}