数字为 sum s 的 k 位整数数组

Posted

技术标签:

【中文标题】数字为 sum s 的 k 位整数数组【英文标题】:Array of k-digit integers with digits of sum s 【发布时间】:2020-12-06 08:58:16 【问题描述】:

我的任务是编写一个程序,找出其位数等于 s 的 k 位数数组的最大和最小元素。例如, 输入:1 3 输出:101 101 输入:2 3 输出:200 101

我在这个例子中得到了正确的输出,但是当我输入“10 10”时程序不工作并且它给出了运行时错误。

#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std; 

  
int main() 
    int s, k; 
    cin >> s >> k;
    int count = 0;
    int fsum = 0, fcnt = 0, scnt = 0;
    vector <int> vec;
    int i = pow(10, k - 1);
    while (i < pow(10, k)) 
          int ssum = 0, num = i;
          while (num)
                ssum += num % 10;
                num /= 10;
          
          if (ssum == s) 
                vec.push_back(i);
                scnt++;
          
          i++;
    
    cout << *max_element(vec.begin(), vec.end()) << " " << *min_element(vec.begin(), vec.end()) << endl;
    return 0; 
 

【问题讨论】:

pow(10, 10) 超出了int 的典型限制。你应该使用更大的整数类型,比如long long 或者使用字符串来存储东西。 你能解释一下测试用例input: 1 3 output: 101 101吗?数字总和等于 2...我可能会漏掉一些东西 在这么大的数字中进行暴力破解太低效了。您将不得不编写更高效的代码。仔细看小例子。想想什么类型的整数大,什么类型的小。 @MikeCAT 是的,我想通了,但现在它显示时间错误,所以我认为我应该为这项任务使用不同的方法 @Damien 在这种情况下,该数组仅包含一个元素 101。因此,它同时是最大元素和最小元素 【参考方案1】:

像往常一样,此类问题不应使用蛮力来回答。这将导致大量的时间和内存消耗。

这样的问题,总是好的算法会赢。

所以,让我们想想。一个要求是找到一个其指定位数之和最大的值。这样一个数字的最大可能总和是多少。这很容易。所有数字都是 9。因此 4 位值的最大可能总和将是 9999 -> 36。我们观察到在数字开头有尽可能多的“9”会很聪明,然后将其余部分放入下一位数字。

示例:5 位数字,总和为 25。

这里我们将从 9 开始,因为它适合,其余为 16。我们可以添加一个额外的 9,其余为 7。所以 99700 是解决方案。所有这些都可以通过整数模除法一次性计算出来。

25 / 9 = 2(整数除法)。所以,我们需要两个。 '9' 在数字的开头。模除法

25 % 9 = 7。这是余数和缺失的数字。

其余请求的位数将用零填充。


对于最小数,我们只需要将最大数取反即可。很简单。

如果最小数量以一开头,那么我们将构建一些简单的特殊处理。

请看下面的代码。

它没有数组或std::vector。它只是即时打印出数字。不需要额外的存储空间。只是数学

#include <iostream>

// If the smallest number shall have a leading 1
constexpr bool Leading1Required true ;

int main() 

    // Here we will store our input values
    unsigned long sumOfDigits, countOfDigits;

    // Do some plausibility checks
    if (!(std::cin >> sumOfDigits >> countOfDigits)) std::cerr << "\nError while reading input\n";
    else if (countOfDigits < 1) std::cerr << "\nError: Count of digits must be greater than 0\n";
    else if (sumOfDigits > countOfDigits * 9) std::cerr << "\nError Sum of digits can never be reached\n";
    else 

        // Ok, now we have some valid values
        // Output maximum value
        for (unsigned long i; i < countOfDigits; ++i) 
            if (i < (sumOfDigits / 9UL)) std::cout << '9';
            if (i == (sumOfDigits / 9UL)) std::cout << (sumOfDigits % 9UL);
            if (i > (sumOfDigits / 9UL)) std::cout << '0';
        
        std::cout << ' ';

        // This will be compiled conditionally
        // In case that we want a leading 1 for the minimum value
        if constexpr (Leading1Required) 
            // So, the reuqested digit sum will be one less, because we want to have a leading 1
            if (sumOfDigits > 0) 
                if (sumOfDigits > 9) 
                    --sumOfDigits;
                    --countOfDigits;

                    // Output the leading one in any case
                    std::cout << '1';
                
            
            else std::cerr << "\nError: Sume of 0 cannot be reached with a leading 1\n";
        

        // Now print the minimum number (is the reverse from the maximum number)
        for (unsigned long i; i < countOfDigits; ++i) 
            if (i > (countOfDigits -sumOfDigits / 9UL)-1) std::cout << '9';
            if (i == (countOfDigits -sumOfDigits / 9UL)-1) std::cout << (sumOfDigits % 9UL);
            if (i < (countOfDigits -sumOfDigits / 9UL)-1) std::cout << '0';
        
        std::cout << '\n';

    
    return 0;

【讨论】:

【参考方案2】:

一个更快的解决方案是处理一个数字数组,并以贪婪的方式分配值。

我们只需要注意,较低值的MSB不能等于0。

input: 10 10
output 9100000000 1000000009

代码: 注意:此代码假定输入是连贯的,即sum &lt;= 9*k。如果没有,可以添加一个简单的测试。

#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
//using namespace std; 

// Print an array, MSB first = last element
void print (const std::vector<int> vec) 
    for (int i = vec.size()-1; i >= 0; --i) 
        std::cout << vec[i];
    
    

int main() 
    int sum, k; 
    std::cin >> sum >> k;
    std::vector<int> vmax(k), vmin(k);
    
    int s = sum;
    int index = k-1;
    while (index >= 0 && s > 0) 
        int digit = std::min(s, 9);
        vmax[index--] = digit;
        s-= digit;
    
    s = sum;
    index = 0;
    while (index < k && s > 0) 
        int digit = std::min(s, 9);
        vmin[index++] = digit;
        s-= digit;
    
    if (vmin[k-1] == 0) 
        vmin[k-1] = 1;
        vmin[index-1]--;
    
    print (vmax);
    std::cout << " ";
    print (vmin);
    std::cout << "\n";
    return 0; 
 

【讨论】:

以上是关于数字为 sum s 的 k 位整数数组的主要内容,如果未能解决你的问题,请参考以下文章

数字和为sum的方法数(动态规划)

c_cpp [阵] 3sum最近。给定n个整数的数组S,在S中找到三个整数,使得总和最接近给定数字target。 Retur

HDOJ4825-Xor Sum(贪心 + Trie + 位运算)

删除一个数的K位使原数变得最小

顺序输出一个整数的各位数字

c语言,输入一个整数 k 和一个字符串 s(k < 字符串s的长度),输出从头开始的s的前k个字符?