LeetCode基础题:排列硬币

LeetCode基础题:排列硬币

考察内容:等差数列的求解

题目描述:

  • 内容:总共有n枚硬币,将它们摆成一个阶梯形状,第k行就必须正好有k枚硬币。
  • 要求:给定一个数字n,找出可形成完整阶梯行的总行数。n是一个非负整数,并且在32位有符号整型的范围内。
  • 分析:题目说的很好听,其实就是等差数列的问题。

在这里我们提供三种方式完成上述题目

1.暴力迭代方式

  • 分析题目我们可知,每一行都是一个等差为1的等差数列,因此只需要使用for循环遍历,直到放不下为止。话不多说,上代码。
代码
	//1.暴力迭代的方法求值
	public static int iterCoins(int n) {
		//因为每一行都是一个等差为1的等差数列,因此只需要使用for循环遍历,直到放不下为止
		for(int i = 1; i<=n; i++) {
			n = n-i;
			//判断此时如果放不下,就跳出
			if(n < i) {
				return i;
			}
		}
		return 0;
	}

时间复杂度为o(n)


2.二分查找实现

  • 因为上面的方法,我们针对于所有的硬币都放完的情况才进行跳出,n的值很大时,整体的世家复杂度机会很高。所以我们可以对上面的方法进行优化。
  • 正确输出的行数肯定是小于n的,所以我们不妨直接先假设我们创建出来的硬币阶梯直接就有n行,然后当n个硬币进行排列的时候自然正确的行数在1-n之间,我们只需要判断,在哪一行我们的n等于我们使用等差数列求和公式的值就行。
代码
public static int iterCoins2(int n) {
		//因为上面的方法,我们针对于所有的硬币都放完的情况才进行跳出。
		//一次我们不妨直接先假设我们创建出来的硬币阶梯直接就有n行
		//然后当n个硬币进行排列的时候自然正确的行数在1-n之间,我们只需要判断,在哪一行我们的
		//n等于我们使用等差数列求和公式的值就行
		int low = 0, high = n;
		while(low<=high) {
			int mid = ((high-low)/2) + low;
			//下面我们直接计算mid行数时的花销
			int cost = ((mid+1)*mid)/2;
			if(cost == n) {
				//此时正好消耗完
				return mid;
			}else if(cost < n) {
				//如果花费过小,说明真实行数要比mid大,左边界右移;
				low = mid+1;
			}else {
				//花费过大
				high = mid-1;
			}
		}
		//最后倘若没找见我们正好相等的情况
		//我们只需要返回最后想要的值就行了,就是上一层完整的层数。
		return high;
	}

此时的时间复杂度我们降低到 log n。


2.牛顿迭代实现

  • 在Java中,我们可以通过实现一个牛顿迭代的函数来求解方程的解。下面是一个示例代码,用于计算方程x^2 - a = 0的解:
public static double sqrt(double a) {
    double x = a;
    double eps = 1e-15;  // 设置迭代停止条件
    while (Math.abs(x - a/x) > eps * x) {  // 判断是否满足停止条件
        x = (x + a/x) / 2.0;  // 更新x的值
    }
    return x;
}
  • 在上述代码中,我们首先将初始值设置为a本身,然后通过不断更新x的值来逼近方程的根。在每次迭代时,我们都判断当前的x是否满足停止条件,即|x - a/x| / x < eps,如果满足,则认为已经得到了足够精确的解,退出迭代并返回结果。

  • 需要注意的是,在实际应用中,我们可能需要对初始值的选择进行优化,以提高迭代的收敛速度和稳定性。另外,对于一些复杂或非线性的方程,可能需要使用更加高级的数值方法来求解,如基于梯度下降的算法等。

  • 牛顿迭代本身就是一种高效求得平方根的方法,这里们正好需要计算等差数列求和的公式,(x*(x+1))/2 = n; 我们对公式进行变形就是 x2 = 2n - x; 我们可以直接 对x2 进行计算,只需求出我们想要得到的x的值就行。

代码
public static int iterCoins3(int n) {
	if(n == 0) {
		return 0;
	}
	    return (int)recall(n,n);
}
//创建递归函数
private static double recall(double x, int n) {
		// TODO Auto-generated method stub
	//首先先将牛顿迭代公式(x+n/x)/2 = x,其中n = x^2,所以此时我们的n的值变成了2n - x
	double res = (x+(2*n - x)/x)/2;
	if(res == x) {
		//相等的时候说明我们已经招待那个花费相同的那一层了
		return x;
	}else {
		return recall(res, n);
	}
		//return 0;
	}

运行

public static void main(String[] args) {
	System.out.println(iterCoins(100));
	System.out.println(iterCoins2(100));
	System.out.println(iterCoins3(100));
}
}

结果

在这里插入图片描述

  • 13
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值