
/** * 暴力算法 * @param n n枚硬币 * @return 形成完整整阶行的总行数 */ private static int arrangeCoins(int n) { for (int i = 1; i < n; i++) { // 循环一次减一行 n = n - i; // 如果剩下的硬币<=i的话,那么剩下的硬币就凑不齐下一行,直接返回i就是可以排列的最多完整行数 if (n <= i) { return i; } } // 如果n=1,直接返回 return n; }
/**
* 二分查找法
* @param n n枚硬币
* @return 形成完整整阶行的总行数
*/
private static int arrangeCoins2(int n) {
int left = 1 , right = n;
while (left <= right) {
int middle = left + (right - left)/2;
// 计算从1到middle行的总硬币
int sum = (1 + middle)*middle/2;
// 总数相等,直接返回middle
if (sum == n) {
return middle;
} else if (sum < n) {
// 总数小于n,则左指针右移
left = middle + 1;
} else {
// 总数大于n,则右指针左移
right = middle - 1;
}
}
return right;
}
/**
* 牛顿迭代法
* @param n n枚硬币
* @return 形成完整整阶行的总行数
*/
private static int arrangeCoins3(int n) {
if (n == 0) {
return n;
}
return (int)sqrt(n,n);
}
/**
* 牛顿迭代的思路就是:根号i 一定在 i/n 和 n 之间,然后 (i/n+n)/2 在无限接近于 根号i,所以递归找到 根号i
* 当 根号i = n时,i/n = n --> (i/n+n)/2 = n;
* @param n
* @param i -> 这里的i需要转换一下,(1+n)*n/2 = i --> n² = 2i - n
* @return
*/
public static double sqrt(double n, int i) {
double res = ((2*i - n)/n + n)/2;
if (res == n) {
return n;
} else {
return sqrt(res,i);
}
}