简体   繁体   English

从n个数字的总和中找到最接近的n

[英]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 . 代码爆发了之后whilemysum变得比你的更大的最接近的总和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.

相关问题 如何找到总和最接近 K 但在多列上的 N 个数字? - How to find N numbers whose sum is closest to K , but over multiple columns? 如何在时间复杂度为 O(n) 的数组中找到和最接近 x 的一对数字? - How to find a pair of numbers in the array which sum is closest to x with O(n) time complexity? 找到N个最接近的数字 - Finding N closest numbers 算法:从n个数组(队列)中找出k个数的最小和 - Algorithm: Find minimum sum of k numbers from n arrays(queues) 在一个序列中找到m个总和为n的数字 - Find m numbers that sum to n in a sequence 对未排序数组中最大的 n 个数求和 - Sum biggest n numbers from unsorted array 子集总和从1…n生成的唯一数 - Unique numbers generated by subset sum from 1…n 从给定的 N 个数字中找出所有可被 3 整除的数字之和。 关于循环的伪代码/算法 - Find the sum of all the numbers divisible by 3 from the given N numbers. Pseudocode/Algorithm regarding loops 查找集合中的数字加起来最接近 n 且小于 n 的数字 - Find the numbers in a collection that add up to the number closest to n which is less than n 如何编写一个计划程序使用n和sum作为参数,并显示所有可以求和的数字(从1到n)? - how to write a scheme program consumes n and sum as parameters, and show all the numbers(from 1 to n) that could sum the sum?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM