How to get the least number after deleting k digits from the input number

前端 未结 11 1203
灰色年华
灰色年华 2020-12-11 05:34

For example, if the input number is 24635, the least number is 23 after deleting any 3 digits.

It\'s not the same as taking the two smalles

相关标签:
11条回答
  • 2020-12-11 05:49

    I think this will do the trick:

    Let's use 532874902352. Try it with anything you want if you feel like it.

    With 532874902352, we will remove 4 digits, or any you want.

    Move 4+1 digits in. 53287|4902352

    Find the smallest number. 2

    Delete all digits before the chosen one. We have now 28749023532; we deleted 2 digits. 2 more.

    Delete 2 digits after the first one. We have 249023532. There we go.

    However, if the digit that would be deleted is the second to last one, delete the last one if it is greater than the second to last one.

    Examples:

    24635, remove 3.

    Move in 3+1.

    2463|5

    Delete all before 2, the smallest.

    24635

    Delete to fulfill the amount of digits needed, 3. But delete 5 instead of 3.

    23

    43331, remove 3.

    Move in 3+1.

    4333|1

    Delete all before 3, the smallest.

    31

    Delete to fulfill the amount of digits needed, 3. We have no more digits to delete.

    It's up to you to implement this method.

    0 讨论(0)
  • 2020-12-11 05:49
    #include <cmath>
    #include <cstdio>
    #include <vector>
    #include <queue>
    #include <functional>
    #include <iostream>
    #include <utility>
    #include <algorithm>
    #define mod 1000000007
    #define ll long long
    using namespace std;
    bool Compare (pair<int, int> p1, pair<int, int> p2)  {
        if (p1.first < p2.first) {
            return true;
        }
        return false;
    }
    int main() {
        priority_queue <pair<int, int>, vector <pair <int, int> >, function<bool (pair <int, int>, pair <int, int>) > > pq (Compare);
        int n, k;
        cin>>n>>k;
        int i = 1;
        while (n) {
            pq.push(make_pair(n%10, i));
            n = n/10;
            i++;
        }
        for(int j =1; j<=k;j++){
            pq.pop();
        }
        int number = pq.top().first;
        int index = pq.top().second;
        int digit = 1;
        pq.pop();
        while(!pq.empty()){
            int current_index = pq.top().second;
            digit = digit * 10;
            if(current_index < index) {
                number = number * 10 + pq.top().first;
            } else {
                number = digit * pq.top().first + number;
            }
            pq.pop();
        }
        cout<<number<<endl;
        return 0;
    }
    

    I solved the question using priority_queue with pair. please let me know if there is any better solution

    0 讨论(0)
  • Offer a recursive approach.

    On each iteration test for success k == 0 ...
    or failure num == 0 as there are no digits left to remove.
    (returning 10 is worse than some other path that would return num.)

    Otherwise recurse in 2 ways:
    1) Keep the least-significant-digit and try with upper digits.
    2) Drop the least-significant-digit and try with upper digits, k--
    Return the better one.

    unsigned reduce(unsigned num, unsigned k) {
      if (k <= 0) {
        return num;  // Success
      }
      if (num == 0) {
        return 10;  // Fail
      }
      unsigned path1 = reduce(num/10, k)*10 + num%10;
      unsigned path2 = reduce(num/10, k-1);
      return path1 < path2 ? path1 : path2;
    }
    
    int main(void) {
      printf("%u\n", reduce(246, 2));
      printf("%u\n", reduce(24635, 3));
      printf("%u\n", reduce(53642, 3));
      printf("%u\n", reduce(21, 1));
    }
    
    2
    23
    32
    1
    

    This solution does not depend on knowing the number of digits, just the number needed to remove.

    0 讨论(0)
  • 2020-12-11 05:52

    The idea is to traverse through the string from the beginning and remove the first digit which is greater than the digit following it. If no such digit exists, remove the last digit.

        class Solution {
        private:
            void removeOneDigit(string& s){
                for(int i=0; i<s.length()-1; i++){
                    if(s[i+1]<s[i]){
                        s.erase(i,1);
                        return;
                    }
                }
                s.erase(s.length()-1,1);
            }
        public:
            string removeKdigits(string num, int k) {
                for(int i=0; i<k; i++){
                    removeOneDigit(num);
                }
                int i=0;
                while(num[i]=='0'){
                    num.erase(0,1);
                }
                if(num.length()==0){return "0";}
                return num;
            }
        };
    
    0 讨论(0)
  • 2020-12-11 05:59

    Knowing that you want to keep digit order certainly makes this solution more difficult.

    I do agree with IVlad that char[]s are not the way to go.

    I think this is a fairly good solution:

    #include <stdio.h>
    #include <math.h>
    #include <limits.h>
    
    #define DIGITS_TO_REMOVE 3 // Assumed to be positive
    
    int recurse(int* foo, int begin, int end, int previous, int max){
        int i;
        int min = begin;
    
        for (i = begin; i <= end; ++i){
            if (foo[min] > foo[i]){
                min = i;
            }
        }
    
        return previous * pow(10, max - end + 1) + (max > end ? recurse(foo, min + 1, end + 1, foo[min], max) : foo[min]);
    }
    
    int main(void) {
        int foo[(const int)ceil(log10(INT_MAX))];
        int bar = 24635; // Assumed to be larger than pow(10, DIGITS_TO_REMOVE) - 1
        int size = ceil(log10(bar));
        int i;
        int min = size - DIGITS_TO_REMOVE;
    
        for (i = 1; bar > 0; bar /= 10, ++i){
            foo[size - i] = bar % 10;
    
            if (i >= DIGITS_TO_REMOVE && foo[size - i] <= foo[min]){
                min = size - i;
            }
        }
    
        printf("%d", recurse(foo, min + 1, DIGITS_TO_REMOVE + 1, foo[min], size - 1));
        return 0;
    }
    

    EDIT:

    IVlad also suggested that I make the solution return an array rather than just an int so it wouldn't be constrained to the size of the return type. There is obviously some work that would need to go into preparing the input and output array so that may not be the goal of the OP, but it's an interesting problem.

    #include <stdio.h>
    
    #define DIGITS_TO_REMOVE 3 // Assumed to be positive
    #define INPUT_SIZE 5 // Assumed to be greater than DIGITS_TO_REMOVE
    
    void recurse(int* input, int* output, int begin, int end){
        int i;
        int min = begin;
    
        for (i = begin; i < end; ++i){
            if (input[min] > input[i]){
                min = i;
            }
        }
        output[end - DIGITS_TO_REMOVE - 1] = input[min];
    
        if (end < INPUT_SIZE){
            recurse(input, output, min + 1, end + 1);
        }
    }
    
    int main(void) {
        int foo[] = { 2, 4, 6, 3, 5 };
        int bar[INPUT_SIZE - DIGITS_TO_REMOVE];
        int i;
    
        recurse(foo, bar, 0, DIGITS_TO_REMOVE + 1);
    
        for (int i = 0; i < INPUT_SIZE - DIGITS_TO_REMOVE; ++i){
            printf("%d", bar[i]);
        }
        return 0;
    }
    
    0 讨论(0)
提交回复
热议问题