Finding the largest three-digits number "within" a number

Viewed 22305

For this question, I need to find the largest three-digit number within a larger number.

Sample Test Case 1:
534535
Output:
535


Sample Test Case 2 :
23457888976
Output :
976


I've tried the following code:
        #include <iostream>
        using namespace std;
        int main() {
        int num;
        cin>>num;
        int len= to_string(num).length();
        int arr[10],lnum=0,max=0;
        for (int i =len-1;i>=0;i--)
        {
        arr[i] = num%10;
        num =num/10;    //to convert int into array
        }
        for (int i=0;i<len-2;i++)
        {
        if (arr[i] >arr[i+1])
            lnum = arr[i]*100+arr[i+1]*10+arr[i];
        if (lnum>max)
            max= lnum;  
        }
        cout<<max;
        return 0;
    }

Although this code seems to work for Test Case 1, it doesn't work for most of the inputs.

(Please do help with this too. )
1. This is for numbers with 10-digits only (that too, most of it have wrong output). What to do in case of bigger numbers?
2. Is there any better way to convert the integer into an array? Or will a string array work in similar way?
3. It's really slow, can anyone help me figure out how to speed this up?
Thanks for any help !!
4 Answers
#include <iostream>
#include <string>
using namespace std;
int main() {
    int i, n;
    string s;
    cin >> s;
    n = (int)s.size();
    if(n<3){
        /* there are less than 3 digits in the input number
        Here, you can print the number itself as it will be largest number or
        print -1 which can state that no 3 digit number exists.
        */
        cout<<-1;
        return 0;
    }
    int maxans = (s[0]-'0')*100 + (s[1]-'0')*10 + (s[2]-'0');
    // storing the first 3 digits as the maximum answer till now.
    int prev = maxans;
    for(i = 3;i<n;i++){
        int cur = (prev%100)*10 + (s[i]-'0'); // using %100 to extract the last two digits and then multiplying by 10 and adding the ith digit to make the next 3 digit number.
        maxans = max(maxans, cur);
        prev = cur;
    }
    cout<<maxans;
    return 0;
}

This code is of time complexity O(n) where n is the length of input string and space complexity O(1)

This approach will work with any big number you can store in variable. The approach is as follows,

First convert number into string and then create an array of all possible numbers of 3 digits as showed below,

Number = 534535
All possible 3 digits number array = ["534", "345", "453", "535"]

Then sort this array, after sorting last element will be max number of three digit, as highlighted below,
Sorted array = ["345", "453", "534", "535"]

Another example,
Number = 23457888976
All possible 3 digits number array = ["234", "345", "457", "578", "788", "888", "889", "897", "976"]
After sorting, last element is max number as highlighted below
Sorted array = ["234", "345", "457", "578", "788", "888", "889", "897", "976"]

Note: Radix sort will perform better then std::sort(), std::sort() offers Quick sort. Radix sort is ideal for string sorting and specially in this case because max bucket size is only 10 (possible range 0-9), but you have to implement radix sort your self.

#include <iostream>

#include <vector>
#include <string>
#include <algorithm>

using std::cout;

std::vector<std::string> allThreeDigitNumbers(const std::string& numStr){

    std::vector<std::string> allNumStr(numStr.size() - 2, std::string("000"));
    std::vector<std::string>::iterator aIt = allNumStr.begin();

    for(std::string::const_iterator it = numStr.cbegin(), lastIt = it + (numStr.size() - 2); lastIt != it; ++it, ++aIt){

        std::copy(it, it + 3, aIt->begin());
    }

    return allNumStr;
}

unsigned maxThreeDigitNumberInNumber(unsigned long long num){

    std::string numStr = std::to_string(num);

    if(numStr.size() < 3){

        return 0;
    }

    std::vector<std::string> allNumStr = allThreeDigitNumbers(numStr);

    std::sort(allNumStr.begin(), allNumStr.end());

    return std::stoul(allNumStr.back());
}

int main(){
    cout<< "Max 3 digits number of 534535 => "<< maxThreeDigitNumberInNumber(534535)<< '\n';
    cout<< "max 3 digits number of 23457888976 => "<< maxThreeDigitNumberInNumber(23457888976)<< '\n';
}

Output

Max 3 digits number of 534535 => 535
max 3 digits number of 23457888976 => 976

Read the comments to understand the code below:

#include <assert.h>
#include <iostream>
#include <boost/hana/functional/partial.hpp>
#include <functional>
#include <range/v3/to_container.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/drop.hpp>
#include <range/v3/view/subrange.hpp>
#include <range/v3/view/take.hpp>
#include <range/v3/algorithm/all_of.hpp>
#include <string>

using namespace boost::hana;
using namespace ranges;
using namespace ranges::views;

auto constexpr is9 = partial(std::equal_to<>{}, 9);

template<typename Range>
Range fun(Range const& r) {
    if (r.size() == 3) {                   // 3 digits only?
        return r;                              // this is the result
    } else if (all_of(r | take(3), is9)) { // 999?
        return r | take(3);                    // nothing better than this!
    } else {                               // otherwise?
        auto tail = r | drop(1);               // drop the first to get the tail
        if (r.front() < tail.front()) {        // if the first is less the the tip of the tail
            return fun(tail);                      // then let the first go and recurse on the tail
        } else {                               // otherwise
            auto result = std::max(                // get the maximum between
                    r | take(3) | to<std::string>, // the current first three
                    fun(tail)   | to<std::string>  // and the result of recursing on the tail
                    );
            return result;                         // and that's the result
        }
    }
    return r;
}

int main() {
    std::string s1 = "534535";
    std::string s2 = "23457888976";
    assert((fun(subrange(s1)) | to<std::string>) == std::string{"535"});
    assert((fun(subrange(s2)) | to<std::string>) == std::string{"976"});
}

The number is treated as a string, and since we need to compare (sub-)strings of length 3, the lexicographic operator< for std::strings gives us the same result as the arithmetic operator< would give for the two corresponding numbers.

The logic is:

  • we start from left and recurse to the right if needed
  • in the case of only 3 digits left, r.size() == 3, we return all of them, return r;
  • in the case of three leading nines, all_of(r | take(3), is9), we trivially return those three, return r | take(3);;
  • otherwise, we take the std::max between the leading 3-digit string, r | take(3) | to<std::string>, and the std::string we obtain by recursing on the rest of the sequence without the first digit, fun(tail) | to<std::string>.

Solution in Python3

#!/usr/bin/env python

num = input("Enter the number : ")

if len(num) == 3:
    print(f"Largest digit is : {num}")
    exit(0)
elif len(num) < 3:
    print(-1)
    exit(0)

maxans = int((num[0].replace("0", "")))*100 + int((num[1].replace("0", "")))*10 + int((num[2].replace("0", "")))
prev = maxans

for i in range(3, 6):
    cur = (prev%100)*10 + int((num[i].replace("0", "")))
    maxans = max(maxans, cur)
    prev = cur

print(f"The Largest num = : {maxans}")
Related