[英]Find closest n from sum of n numbers
I am trying to solve for closest value of n when I am given a sum of first n numbers. 当我得到前n个数字的总和时,我试图求解n的最接近值。 Meaning if I have sum as 60, my n should be 10 as the sum of first 10 numbers is 55, if I include 11 the sum would be 66, exceeding my required sum. 意味着如果我的总和为60,则我的n应该为10,因为前10个数字的总和为55,如果我包括11,则总和为66,超出了我要求的总和。
int num=1, mysum = 0;
int givensum=60;
while (mysum < givensum) {
mysum += num;
num++;
}
cout<<num-1;
return 0;
The other way I can think of solving this is by solving for quadratic equation 我想解决这个问题的另一种方法是解决二次方程式
n(n+1) / 2 = givensum
and get n from it. n(n+1) / 2 = givensum
和并从中获得n 。 Is there any other way to solve this problem? 还有其他解决方法吗?
I don't think there is a better way than solving the quadratic equation . 我认为没有比解决二次方程更好的方法了。 It is pretty straightforward, 这很简单,
n*(n+1)/2 = sum
n^2 + n - sum*2 = 0
assumin ax^2 + bx + c = 0
a = 1, b = 1, c = -2*sum
since we don't need the negative answer: 因为我们不需要否定答案:
n = ( -b + sqrt(b^2 - 4ac) ) / 2a
This is the implementation: 这是实现:
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int sum = 60;
int a = 1;
int b = 1;
int c = -sum*2;
double delta = b*b - 4*a*c;
if ( delta >= 0 ){
double x1 = -b + sqrt(delta);
//double x2 = -b - sqrt(delta); // we don't need the negative answer
x1 /= 2*a;
//x2 /= 2*a;
cout << x1 << endl;
}
else {
cout << "no result";
}
}
the result is a floating point number, if you want the sum of n elements to be less than or equal to the input sum you should round it down with floor
function. 结果是一个浮点数,如果您希望n个元素的总和小于或等于输入总和,则应使用floor
函数将其四舍五入。
Consider the function f(n) = n*(n+1)/2
which yields the sum of first n integers. 考虑函数f(n) = n*(n+1)/2
,该函数得出前n个整数的和。 This function is strictly increasing. 此功能正在严格增加。 So you can use binary search to find n when the value for f(n)
is given to you: 因此,当给定f(n)
的值时,您可以使用二进制搜索来找到n :
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int sum = 61;
int low = 1, high = sum, mid;
while ( low < high ){
mid = ceil ( (low+high)/2.0 );
int s = mid*(mid+1)/2;
if ( s > sum ){
high = mid-1;
} else if ( s < sum ) {
low = mid;
} else {
low = mid;
break;
}
}
cout << low << endl;
}
So we want to find an integer n
such that (n+1)*n/2 <= y < (n+2)*(n+1)/2
所以我们想找到一个整数n
使得(n+1)*n/2 <= y < (n+2)*(n+1)/2
Solving the quadratic equation f(x)=y
, where f(x)=(x+1)*x/2
can be done with floating point arithmetic, then taking n
as integer part of x
. 求解二次方程f(x)=y
,其中f(x)=(x+1)*x/2
可以用浮点算法完成,然后将n
用作x
整数部分。
But we don't really need floating point because we just want the integer part of the result, we can also do it with a Newton-Raphson iteration https://en.wikipedia.org/wiki/Newton%27s_method 但是我们实际上并不需要浮点,因为我们只想要结果的整数部分,我们还可以使用Newton-Raphson迭代https://en.wikipedia.org/wiki/Newton%27s_method来实现
The derivative of f(x)
is f'(x)=(x+(1/2))
. f(x)
的导数是f'(x)=(x+(1/2))
。 Not a good integer, but we can all multiply by 2, and write the loop like this: (this is Smalltalk, but that does not really matter): 这不是一个很好的整数,但是我们都可以乘以2,然后编写这样的循环:(这是Smalltalk,但这并不重要):
Integer>>invSumFloor
"Return the integer n such that (1 to: n) sum <= self < (1 to: n+1) sum"
| guess delta y2 |
y2 := self * 2.
guess := 1 bitShift: y2 highBit + 1 // 2.
[
delta := ((guess + 1) * guess - y2) // (guess * 2 + 1).
delta = 0 ]
whileFalse: [ guess := guess - delta ].
^guess - 1
So we are iterating like this: 所以我们这样迭代:
x(n+1) = x(n) - (2*f(x(n))-2*y)/(2*f'(x(n)))
But instead of taking an exact division, we use //
which is the quotient rounded down to nearest integer. 但是,我们不采用精确除法,而是使用//
向下舍入到最接近整数的商。
Normally, we should test whether the guess is overstimated or not in the final stage. 通常,我们应该测试在最后阶段猜测是否被过度估计。
But here, we arrange to have the initial guess be an overestimate of the result, but not too much overestimated so that the guess will allways stay overestimated. 但是在这里,我们安排使最初的猜测高估结果,但又不要过高地估计,以使猜测始终会被高估。 Like this we can simply subtract 1 in final stage. 这样,我们可以在最后阶段简单地减去1。 Above implementation uses a rough guess of first bit position as initial x
value. 上面的实现使用第一位位置的粗略猜测作为初始x
值。
We can then check the implementation on first ten thousand natural integers with: 然后,我们可以使用以下命令检查前一万个自然整数的实现:
(1 to: 10000) allSatisfy: [:y |
| n sum |
n := y invSumFloor.
sum := (1 to: n) sum.
(sum <= y and: [y < (sum + n + 1)])].
which answers true
回答true
What's nice with Smalltalk is that you can then try things like this: Smalltalk的优点在于您可以尝试如下操作:
80 factorial invSumFloor.
And get something like: 并得到类似:
378337037695924775539900121166451777161332730835021256527654
You here see that Newton Raphson converges rapidly (7 iterations in above example). 您在这里看到Newton Raphson迅速收敛(在上面的示例中为7次迭代)。 This is very different from the initial naive iteration. 这与初始的天真的迭代有很大的不同。
After the code breaks out of the while
, mysum
becomes the closest sum that is greater than your givensum
. 代码爆发了之后while
, mysum
变得比你的更大的最接近的总和givensum
。 For the example you have given, the while
loop gets executed because 55 is less than 60
, and the mysum
becomes 66 and num
becomes 12 in the last execution of the loop just before it stops. 对于您给出的示例,由于55 is less than 60
,因此执行while
循环,因为mysum
在循环的最后一次执行中变为66,而num
变为12,就在它停止之前。 After this step, because 66 is not less than 60
, the while
does not get executed again. 在此步骤之后,由于66 is not less than 60
,因此while
不会再次执行。 Therefore, you should decrease the mysum
by num-2
. 因此,应将mysum
减少num-2
。
cout<<num-2;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.