Interview puzzle: broken calculator

Time limit: 2s / Stack limit: 256MB / Memory limit: 256MB

Problem Dave's calculator is broken. It stops when more than K different digits are displayed.

Dave wants to enter integer A, but if he enters this number correctly, the calculator may stop. Instead, he enters the nearest integer, which will not stop the calculator.

Print the difference between input Dave and integer A.

Input

Data entry will be given in the following format from standard input.

A K

      

  • On the first line, you will be given an integer A (1 ≦ A ≦ 10 ^ 15), the integer Dave wants to enter, followed by a space and K (1 ≦ K ≦ 10), the number of different digits his calculator can recognize ...

Output

Print the minimum difference between the input Dave and the integer A on one line. Be sure to insert a line break at the end of the output.


Input example 1

1234 2

      

Output example 1

12

      

In this case, Dave can only use up to two different digits. It will enter the closest integer 1222, so the difference is 12.


Input example 2

7328495 10

      

Output example 2

0

      

In this case, the Dave calculator will not break at all. He can enter the given integer A as is.


Input example 3

800000 1

      

Output example 3

22223

      

Dave can only use one digit, so 777777 is the closest integer.


Input example 4

262004 2

      

Output example 4

218

      

The closest integer is 262222.


I solved the problem with a brute force solution ...

I try every possible situation where I am in 1 <= I <A or <I <= 10 ^ 15.

I will get two solutions with K different digits and find the minimum difference between A and solutions.

This is a simple solution.

When A is greater, execution will exceed the threshold of 2 seconds.

Is there a sensible and efficient way to solve it?

+3


source to share


6 answers


First part: Choose which k digits (out of 10 possible) are used in the result
With bit math (binomial coefficient) it is easy to calculate the number of different combinations of digits for a given k.
There are up to 252 choices (252 if k = 5, not so many).

If it is not clear what I am saying: for k = 2 there is 01,02,03,...09,12,13,...,19,23,24,...,89


No, for example. 11 because it's only 1, but k = 2 allows two different digits.
And no, for example. 90 because it's the same as 09, 91 = 19, etc.
The count of these possible combinations is 252 at k = 5, and it will not get bigger.

Finding all (up to) 252 possibilities for the current k
and iterating over them in a loop shouldn't be too hard.

For each opportunity, do the following:
{

Inside the loop, we have A, K, and the currently selected valid digits
to solve (the latter is of course different on each iteration of the loop)
Let's take A = 12899, K = 3, 123 digits as an example.
Now search for the first digit (left to right) that is not allowed.
In the example it would be 12 8 99 because 1 and 2 to the left of it are allowed.



Replace this (8) with the next least significant digit allowed (2) if there is one and replace everything to the right of it with the highest possible digit (3 too).
12899 => 12 3 99 => 123 33
Store the result 12333 somewhere in an array, etc.
If there was no next lowest possible digit, do nothing (nothing goes into the array)

(Correct addition with transfer introduces a new digit to the left of the changed one,
that is, disabled. A solution with this new digit will be found
when the loop comes to this digit)

Then the same thing again in the other direction:
Replace the found digit with the next higher possible one and everything is correct with the smallest one. This is also in the array, of
course, only if there was the next highest possible digit.
In the case of 12899, the only higher replacement for 8 would be 9,
but 9 is not possible (only 123).

}

After completing the entire loop (and each iteration has produced up to two new entries in the array), you have up to 502 possible solutions to the problem.
It remains only to check which one is the best (i.e. Calculate the difference to A for each record and take the solution, the minimum difference)

0


source


At each step, you can use the digit you want, digit + 1 (mod 10), digit -1 (mod 10), or whatever digit you have used before. When you are done with numbers, you can only use the numbers that you used before.

This creates a tree. At each step, take the current states and calculate all possible new states at the next level down.

You can trim the tree as you go by deleting all subsequent delta steps that are some distance from the smallest delta of any of the following steps.



This is essentially a linear programming problem.

Below is the complete algorithm! Maybe someone can fine-tune the decision on which branches to cut to make it even faster.

using System.IO;
using System;
using System.Collections.Generic;
using System.Linq;

public static class Converter
{
    public static int ToInt(this IEnumerable<int> values)
    {
        return values.Aggregate(0, (total, v) => total * 10 + v);
    }

    public static IEnumerable<int> ToList (this int value)
    {
        if (value == 0) return Enumerable.Empty<int>();
        else return value.ToString().Select(x => (int)x - '0').ToList();
    }
}


class Program
{
    static void Main(string[] args)
    {
        //int desired = 262004;
        //int digits = 2;

        int desired = 800000;
        int digits = 1;

        IEnumerable<State> currentStates = new[] { new State(0, 0, desired, digits) };

        foreach (var digit in desired.ToList())
        {
            var nextStates = currentStates.SelectMany(x => x.NextPossibleStates());
            foreach (var state in nextStates.OrderBy(s => s.Delta()).Take(10))
            {
                Console.WriteLine(state.ToString());
            }
            currentStates = nextStates;
            Console.WriteLine("------------");
        }

        Console.ReadKey();
    }

    public class State
    {
        int index;
        int current;
        int desired;
        int digitsRemaining;

        private int desiredToNow()
        {
            return desired.ToList().Take(index).ToInt();
        }

        public int Delta()
        {
            return Math.Abs(desiredToNow() - current);
        }

        public State(int index, int current, int desired, int digitsRemaining)
        {
            this.index = index;
            this.current = current;
            this.desired = desired;
            this.digitsRemaining = digitsRemaining;
        }

        private State Next (int nextDigit, int digitsRemaining)
        {
            return new State(this.index + 1, this.current * 10 + nextDigit, this.desired, digitsRemaining);
        }

        private IEnumerable<int> NextPossibleDigitsWithDuplicates()
        {
            if (this.digitsRemaining > 0)
            {
                int nextDesiredDigit = desired.ToList().Skip(index).First();
                yield return nextDesiredDigit;
                yield return (nextDesiredDigit + 9) % 10;
                yield return (nextDesiredDigit + 1) % 10;
            }
            // Any previously used digit is OK
            foreach (int i in this.current.ToList())
                yield return i;
        }

        public IEnumerable<State> NextPossibleStates()
        {
            var possibles = this.NextPossibleDigitsWithDuplicates().Distinct();
            var possiblesUsingExistingDigits = possibles.Where(p => this.current.ToList().Contains(p));
            var possiblesUsingNewDigits = possibles.Where(p => !this.current.ToList().Contains(p));

            var states = possiblesUsingExistingDigits.Select(p => Next(p, this.digitsRemaining))
                .Concat(possiblesUsingNewDigits.Select(p => Next(p, this.digitsRemaining - 1)))
                .ToList();

            var bestDelta = states.Min(s => s.Delta());
            // Now reject any that can never be better
            // Guessing on the '2' here ...
            var validStates = states.Where(s => s.Delta() < bestDelta + 2);
            return validStates;
        }

        public override string ToString()
        {
            return this.current + " d=" + this.Delta() + " remaining " + this.digitsRemaining;
        }
    }
}

      

0


source


After thinking a little about the problem, I think the best way is to use the A * algorithm, which assigns numbers from left to right. For this, we need an estimate of the lower bound for the error of a partial solution. Simple possibility:

  • if the already set numbers are exactly the same as in the problem, the border is 0
  • if the already given numbers are lower than in the problem, replace the missing numbers with 9 to get the lower bound
  • if the already set digits are higher than in the problem, replace the missing digits with 0 to get the lower bound

Taking an approximate problem 12899 3

, the algorithm will work as follows:

Run node

node      best      error
xxxxx     12899         0

      

expansion of the most promising partial solution xxxxx

node      best      error
0xxxx     09999      2900
1xxxx     12899         0
2xxxx     20000      7101
3xxxx     30000     17101
4xxxx     40000     27101
5xxxx     50000     37101
6xxxx     60000     47101
7xxxx     70000     57101
8xxxx     80000     67101
9xxxx     90000     77101

      

Extension of the most promising partial solution 1xxxx

node      best      error
0xxxx     09999      2900

10xxx     10999      1900
11xxx     11999       900
12xxx     12899         0
13xxx     13000       101
14xxx     14000      1101
15xxx     15000      2101
16xxx     16000      3101
17xxx     17000      4101
18xxx     18000      5101
19xxx     19000      6101

2xxxx     20000      7101
3xxxx     30000     17101
4xxxx     40000     27101
5xxxx     50000     37101
6xxxx     60000     47101
7xxxx     70000     57101
8xxxx     80000     67101
9xxxx     90000     77101

      

Expansion of the most promising partial solution 12xxx

node      best      error
0xxxx     09999      2900
10xxx     10999      1900
11xxx     11999       900

120xx     12099       800
121xx     12199       700
122xx     12299       600
123xx     12399       500
124xx     12499       400
125xx     12599       300
126xx     12699       200
127xx     12799       100
128xx     12899         0
129xx     12900         1

13xxx     13000       101
14xxx     14000      1101
15xxx     15000      2101
16xxx     16000      3101
17xxx     17000      4101
18xxx     18000      5101
19xxx     19000      6101
2xxxx     20000      7101
3xxxx     30000     17101
4xxxx     40000     27101
5xxxx     50000     37101
6xxxx     60000     47101
7xxxx     70000     57101
8xxxx     80000     67101
9xxxx     90000     77101

      

Extension of the most promising partial solution 128xx (now only numbers 1, 2 and 8 are available)

node      best      error
0xxxx     09999      2900
10xxx     10999      1900
11xxx     11999       900
120xx     12099       800
121xx     12199       700
122xx     12299       600
123xx     12399       500
124xx     12499       400
125xx     12599       300
126xx     12699       200
127xx     12799       100

1281x     12819        80
1282x     12829        70
1288x     12889        10

129xx     12900         1
13xxx     13000       101
14xxx     14000      1101
15xxx     15000      2101
16xxx     16000      3101
17xxx     17000      4101
18xxx     18000      5101
19xxx     19000      6101
2xxxx     20000      7101
3xxxx     30000     17101
4xxxx     40000     27101
5xxxx     50000     37101
6xxxx     60000     47101
7xxxx     70000     57101
8xxxx     80000     67101
9xxxx     90000     77101

      

Extension of the most promising partial solution 129xx (now only numbers 1, 2 and 9 are available)

node      best      error
0xxxx     09999      2900
10xxx     10999      1900
11xxx     11999       900
120xx     12099       800
121xx     12199       700
122xx     12299       600
123xx     12399       500
124xx     12499       400
125xx     12599       300
126xx     12699       200
127xx     12799       100
1281x     12819        80
1282x     12829        70
1288x     12889        10

1291x     12910        11
1292x     12920        21
1299x     12990        91

13xxx     13000       101
14xxx     14000      1101
15xxx     15000      2101
16xxx     16000      3101
17xxx     17000      4101
18xxx     18000      5101
19xxx     19000      6101
2xxxx     20000      7101
3xxxx     30000     17101
4xxxx     40000     27101
5xxxx     50000     37101
6xxxx     60000     47101
7xxxx     70000     57101
8xxxx     80000     67101
9xxxx     90000     77101

      

Expanding the most promising partial solution 1288x (now only numbers 1, 2 and 8 are available)

node      best      error
0xxxx     09999      2900
10xxx     10999      1900
11xxx     11999       900
120xx     12099       800
121xx     12199       700
122xx     12299       600
123xx     12399       500
124xx     12499       400
125xx     12599       300
126xx     12699       200
127xx     12799       100
1281x     12819        80
1282x     12829        70

12881     12881        18
12882     12882        17
12888     12888        11  <-- optimal solution found

1291x     12910        11
1292x     12920        21
1299x     12990        91
13xxx     13000       101
14xxx     14000      1101
15xxx     15000      2101
16xxx     16000      3101
17xxx     17000      4101
18xxx     18000      5101
19xxx     19000      6101
2xxxx     20000      7101
3xxxx     30000     17101
4xxxx     40000     27101
5xxxx     50000     37101
6xxxx     60000     47101
7xxxx     70000     57101
8xxxx     80000     67101
9xxxx     90000     77101

      

It still doesn't cover that the optimal solution might have more digits than the original number (not sure if that's even possible), but you get the idea ...

0


source


For K = 10, the solution is trivial. The difference is 0.


If the original number uses less than or equal to K single digit. The difference is 0. For example, 987777 5

use 3 different digits that are less than K (= 5).


For K = 1,

A number with length n will be associated with 999 ... 999 (n-digit) and 999 ... 999 ((n-1) -digit). This means 587 is bound by 999 and 99

. Hence the solution must be either an n-digit length number or 999 ... 999 ((n-1) -digit).

Let the leading digit of the number be a

(5 in 587), denote b=a+1

and c=a-1

. Compare the numbers with aaa...aaa

, bbb...bbb

, ccc...ccc

(the whole n-bit length). Note that this is just a test of no more than 2 of them.

  • If original number = aaa...aaa

    , the difference is 0.
  • If original number > aaa...aaa

    , keep comparing with bbb...bbb

    .
  • If original number < aaa...aaa

    , keep comparing with ccc...ccc

    .

Rule for K = 1, if b=10

, ignore bbb...bbb

, since aaa...aaa = 999...999

, upper bound. if c=0

, change ccc...ccc

to 999...999

((n-1) -digit) to check the lower bound, for example10000 1 -> 9999


For K in the range [2.9], note that first K-1 distinct digit from left to right must be used

. For example, in this case it is necessary to use 9988898988981234 3

, 2 figures 8 and 9.

Evidence:

Fact:

  • Number of individual digits in original number> K
  • K-1! = 0

We can always form two values z000...000

and z999...999

by using K a different digit where z

is the form over K-1 different digit ( z = 998889898898

in the example above) and assign the K th digit as 0 or 9 (ignore the fact that 0 or 9 can be used K-1

as not important)

With z000...000

and z999...999

( 9988898988980000

and 9988898988989999

) the optimal solution is associated with two values. If z changes to z + 1 or z-1, the difference will increase, which doesn't make sense. Thus, the z part will always be used and first K-1 distinct digit from left to right must be used

.

End of proof

At the first meeting of K-th separate numbers (leading figure on the right after the z-often referred to as t

), you can consider three possible cases t

, t+1

and t-1

.

Let's start with t

. Usage t

will use the entire K digit, so no digit can be assigned. Keep checking the digit on the right side until we come across a digit that is not in those significant K digits. This time we choose no more than two. The closest digit in K that is greater than the encounter digit and the closest digit in K that is less than the encounter digit. Using the larger nearest digit in K will result in a quantity larger than the original number, so the remaining digit should be minimized by choosing the smallest digit in K. Similarly, the remaining digit for the smaller nearest digit in the case of K will be the largest digit in K.

In case t+1

it only needs to be checked if there is no larger nearest digit in K in case t

. Usage t+1

will always be greater than the original number, we need to minimize the remaining digit. Note that there t+1

may be one of the digits in K-1, we have a free digit and therefore include 0

(if 0

not in K-1). We can then select the smallest digit in K (or K-1 if t+1

u 0

are in K-1

) for the remaining digit.

In the case t-1

it is only necessary to check when there is no less than the nearest digit in K in the case t

. Usage t-1

will always be less than the original, we need to maximize the remaining figure. Note that there t-1

may be one of the digits in K-1, we have a free digit, and therefore include 9

(if 9

not in K-1). We can then select the largest digit in K (or K-1 if t-1

u 9

are in K-1

) for the remaining digit.

0


source


The solution time is O (len (A)). Find min | A - B |, with a different number of K from K. First, to remove abs, we must find B1 with the condition (min (Bi | Bi> = A, with a different number of digits),

  • Let A = a1a2 ... an, B1 = b1b2 ... bn, find the longest sequence that ai = bi, until the different number exceeds K. Suppose that a1-> aj = b1-> bj

  • If j == n, then B1 = A

  • From the set {a1, a2, ..., aj}, we find the minimum number greater than b [j + 1]

If we find ak (1 <= k <= j), then let b [j + 1] = ak, and the rest of b [j + 1] → bn is filled with min {a1, a2, ..., a;}

If not, we change bj from aj to a [j] +1. For the rest b [j + 1] → bn,

If [j] +1 is in the set {a1, a2, ..., aj-1}, that means we can still press one digit, we choose 0 as the complement. b [j + 1] → bn are filled with 0.

If a [j] +1 is not in the set {a1, a2, ..., aj-1}, choose min {a1, a2, ..., aj-1, a [j] +1} as the value, which is filled with b [j + 1] → bn

Similarity, we can find the closest B2 number that is less than A,

After that we just compare B1-A with A-B2, choose the minimum.

Following the C ++ code:

    #include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <sstream>
using namespace std;

string target_num;
string up_num;
string down_num;
int K;

bool hash_key[10];
bool hash_copy[10];

int find_closet_k(int c, bool up) {
 int i = c;
 while(true) {
  if (hash_key[i]) {
   return i;
  }

  if(up) {
   ++i;
   if (10 <= i) {
    break;
   }
  } else {
   --i;
   if (i < 0) {
    break;
   }
  }

 }
 return -1;
}

char min_k() {
 for (int i = 0; i < 10; ++i) {
  if (hash_key[i]) {
   return '0' + i;
  }
 }
}

char max_k() {
 for (int i = 9; 0 <= i; --i) {
  if (hash_key[i]) {
   return '0' + i;
  }
 }
}

bool is_head_zero(int v, string num,int end_pos) {
 if (0 == v) {
  for (int i = 0; i < end_pos; ++i) {
   if (num[i] != '0') {
    return false;
   }
  }
  return true;
 }
 return false;
}

int string2int(string s) {
 std::stringstream ss;
 ss << s;
 int is;
 ss >> is;
 return is;
}

void find_closest() {
 int k = 0;
 int i = 0;
 for (i = 0; i < target_num.size(); ++i) {
  int c = target_num[i] - '0';
  if (!hash_key[c]) {
   if (k == K) {
    break;
   }
   hash_key[c] = true;
   ++k;
  }
  up_num.push_back(target_num[i]);
  down_num.push_back(target_num[i]);
 }

 if (i == target_num.size()) {
  printf("0\n");
  return;
 }

 copy(hash_key, hash_key + 10, hash_copy);
 int j = i - 1;
 up_num.resize(target_num.size());
 int c = target_num[j + 1] - '0';
 int v = find_closet_k(c, true);
 if (v == -1) {
  int aj = target_num[j] - '0';
  up_num[j] = aj + 1 + '0';
  if (hash_key[aj + 1]) {
   //only used K - 1, use 0 as min_k();
   fill(up_num.begin() + j + 1, up_num.end(), '0');
  } else {
   hash_key[aj] = false;
   hash_key[aj + 1] = true;
   fill(up_num.begin() + j + 1, up_num.end(), min_k());
  }
 } else {
  up_num[j + 1] = v + '0';
  fill(up_num.begin() + j + 1, up_num.end(), min_k());
 }

 copy(hash_copy, hash_copy + 10, hash_key);
 j = i - 1;
 down_num.resize(target_num.size());
 v = find_closet_k(c, false);
 if (v == -1) {
  int aj = target_num[j] - '0';
  down_num[j] = aj - 1 + '0';
  if (hash_key[aj - 1] || is_head_zero(aj - 1,down_num, j)) {
   fill(down_num.begin() + j + 1, down_num.end(), '9');
  } else {
   hash_key[aj] = false;
   hash_key[aj -1] = true;
   fill(down_num.begin() + j + 1, down_num.end(), max_k());
  }
 } else {
  down_num[j + 1] = v + '0';
  fill(down_num.begin() + j + 1, down_num.end(), max_k());
 }

 unsigned __int64 upi;
 unsigned __int64 targeti;
 unsigned __int64 downi;
 sscanf(up_num.c_str(), "%lld", &upi);
 sscanf(target_num.c_str(),"%lld",&targeti);
 sscanf(down_num.c_str(),"%lld",&downi);

 unsigned __int64 delta = min(upi - targeti, targeti - downi);
 printf("%lld\n", delta);

}

int main(){
 while (true) {
  cin>>target_num>>K;
  fill(hash_key, hash_key + 10, false);
  find_closest();
  up_num.clear();
  down_num.clear();
  target_num.clear();
 }

}

      

0


source


Change N2

at each step, check if:

a) adding a closeset of a possible digit less then the current one and then maximizing the remaining digits is better than the current answer

b) put the largest possible digit higher then the current one and then minimize the remaining digits better than the current answer

then if possible put the same digit and then move on to the next digit

-1


source







All Articles