简体   繁体   中英

Array of k-digit integers with digits of sum s

my task is to make a program that finds max and min element of array of k-digit numbers whose digits are equal to s. For example, input: 1 3 output: 101 101 input: 2 3 output: 200 101

I've got correct outputs for this examples, but when I enter "10 10" program does not work and it gives runtime error.

#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; 
} 

As usual, such questions should not be answered using brute force. This will result in high time and memory consumption.

With this kind of questions, always the good algorithm will win.

So, let's think. One requirement is to find a value with the maximum sum of its specified number of digits. What would be the maximum possible sum of such a number. That is easy. All digits will be 9. So the maximum possible sum for a 4 digit value will be 9999 -> 36. We observe that it will be clever to have as much as possible '9's at the beginning of the number, then put the rest in the next digit.

Example: 5 digits with sum 25.

Here we will start with a nine, because it fits, the the rest is 16. We can add an additional 9, the rest is seven. So 99700 is the solution. All this can be calculated in one shot by integer an modulo division.

25 / 9 = 2 (integer division). So, we need two. '9's at the beginning of the number. The modulo division

25 % 9 = 7. That is the rest and the missing digit.

The rest of the requested count of digits will be filled with zero.


For the minimum number, we just need to reverse the maximum number. Very simple.

If the minimum number shall start with one, then we will build in some easy special handling.

Please see the following code.

It has no array or std::vector . It just prints out the digits on the fly. No additional storage needed. Just maths

#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;
}

A much faster solution consists in working with a array of digits, and just assign the values in a greedy way.

We just have to pay attention that the MSB of the lower value cannot be equal to 0.

input: 10 10
output 9100000000 1000000009

Code:
Note: this code assumes that the input is coherent, ie sum <= 9*k . If not, a simple test can be added.

#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; 
} 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM