* 排列硬币 * https://leetcode-cn.com/problems/arranging-coins/description/ * 你总共有 n 枚硬币,你需要将它们摆成一个阶梯形状,第 k 行就必须正好有 k 枚硬币。 * 给定一个数字 n,找出可形成完整阶梯行的总行数。 * n 是一个非负整数,并且在32位有符号整型的范围内。 * 示例 1: * n = 5 * 硬币可排列成以下几行: * ¤ * ¤ ¤ * ¤ ¤ * 因为第三行不完整,所以返回2.
有三种解法,分别是暴力解法,二分查找,数学解法。时间复杂度分别是O(N),O(LogN),O(1)。
public class ArrangeCoins {
//有三种解法
//方法一,暴力法,时间复杂度为O(N),直接while循环,剩余值大于等于下一行行号
public static int arrangeCoins1(int n) {
if (n < 1) {
return 0;
}
int rowNum = 1;
int remain = n - rowNum;
while (remain >= rowNum + 1) {//rowNum行有rowNum个硬币,所以remain值必须大于等于下一行rowNum+1
rowNum++;//统计有效的rowNum
remain = remain - rowNum;//更新剩余的值
}
return rowNum;
}
//方法二,二分查找法,时间复杂度O(LogN).思路就是找到一个k,使得所有和刚好大于n,那么k-1就是答案。这个假设是基于行号k=n。
public static int arrangeCoins2(int n) {
//公式 1+2+3+...+n = ((1+n)/2)*n,也就是首尾的均值乘以n等于和
if(n == 1){
return 1;
}
int left = 0;//从1开始
int right = n;
while (left <= right) {
int mid = (left + right) / 2;
//和
long tmpSum = mid*(mid+1)/2;//实际等于mid*(mid+1)/2
if (tmpSum < n) {
left = mid + 1;
} else {
right = mid -1 ;
}
}
return left - 1;//最后left就是mid,而这mid刚好就是让所有和大于n的存在,所以需要减去1
}
//方法三,就是数学方法
//时间复杂度O(1),利用了等差数列的性质,等式n = (1 + x) * x / 2,
//一元二次方程的求根公式 x = (-1 + sqrt(8 * n + 1)) / 2
public static void main(String[] args) {
System.out.println(arrangeCoins1(5));
System.out.println(arrangeCoins2(5));
}
}