总共n枚硬币,将他们摆成一个阶梯形状,第k行有k个硬币。返回可形成完整阶梯行的总行数。
迭代:从低到高一个一个排列,最终看看有多少行。每次放完硬币都做一次判断,如果剩下的硬币不够放下一行,那么返回当前行数即可。
二分查找:我们知道对于n个硬币,能排列出的绝对是小于等于n的,因此,我们只需要利用二分法在1-n区间内不断寻找符合条件的行数即可。对于任意行i,填满到本行所需的硬币数为等差数列求和,(1+2+……+i),每次通过判断即可求出正确答案。时间复杂度O(logn)。
牛顿迭代:分析上面的二分查找,其中有一个等差数列求和公式。假设当前为i行,那么总共需要硬币数量n=(i^2+i)/2,变形后为2n-i = i^2。由此可知,我们需要利用牛顿迭代求出i的平方根。通过求平均值不断逼近i即可
上代码:
//10.排列硬币
public class ArrangeCoin {
public static void main(String[] args) {
System.out.println(arrangeCoins(100));
System.out.println(arrangeCoins2(100));
System.out.println(arrangeCoins3(100));
}
//迭代
public static int arrangeCoins(int n){
for (int i=1;i<=n;i++){
n-=i;
if (n<=i){
return i;
}
}
return -1;
}
//二分查找
public static int arrangeCoins2(int n){
int low =0,high=n;
while (low<=high){
int mid = (high-low)/2+low;
int cost = (mid*mid+mid)/2;
if (cost==n){
return mid;
}else if (cost>n){
high=mid-1;
}else {
low=mid+1;
}
}
return high;
}
//牛顿迭代
public static int arrangeCoins3(int n){
if (n==0){
return -1;
}
return (int)sqrt(n,n);
}
private static double sqrt(double x, int n) {
double res = (x+(2*n-x)/x)/2;
if (res==x){
return x;
}else {
return sqrt(res,n);
}
}
}
结果:
13
13
13