动态编程:计算两者之间的数字

时间:2017-11-27 23:44:03

标签: c++ string algorithm optimization dynamic-programming

鉴于两个数字XY,它们之间存在多少个数字,至少有一半数字相同?例如,11224444可行,而11234112233则不起作用。

显然,最直接的方法是从X开始并一直递增到Y,然后检查每个数字,但这太慢了,因为{的边界{1}}和X介于Y100之间。我知道它是某种形式的动态编程,我应该使用字符串来表示数字,但我无法进一步了解。

任何帮助都会被接受。谢谢!

3 个答案:

答案 0 :(得分:7)

我会在一些步骤中解释你:

第一步:

要解决XY之间的这种范围问题,请务必在0 to X0 to Y-1之间进行计算,然后减去结果。即如果你有像f(N)这样的函数来计算在0和N之间至少有一半数字相同的数字,那么你的最终结果是:

f(X) - f(Y-1)

第二步:

接下来我们要计算f(N)。我们将这个函数分成2个子函数,一个用于计算具有相同数字位数的数字的结果用N(让我们称之为f_equal),另一个用于计算数字少于N的限定数字(让我们称之为f_less) 。例如。如果N是19354,我们计算0到9999之间的限定数字,然后在另一种方法中计算10000到19354之间的最喜欢的数字,之后我们总结结果。接下来,我将向您解释如何实现这两种方法。

第三步:

在这里,我们要计算f_less方法。你可以通过一些数学来做到这一点,但我总是喜欢写一个简单的DP来解决这些任务。我会编写递归函数,无论你是否可以使用memoization,或者你可以通过一些循环自下而上(我将把它留作练习)。

long long f_less(int curDigit, int favNum, int favNumCountSoFar, int nonFavNum, int nonFavNumCountSoFar, int maxDigit){
    if(curDigit == maxDigit ){
        //for numbers with even maxDigit there may be a case when we have 2 favorite numbers
        //and we should count them only once. like 522552
        if(favNumCountSoFar*2 == maxDigit && favNumCountSoFar == nonFavNumCountSoFar) return 1;
        if(2*favNumCountSoFar >= maxDigit) return 2;
        return 0;
    }
    long long res = 0;
    for(int i=(curDigit==0?1:0);i<=9;++i) //skip the leading zero
        if(i==favNum)
            res += f_less(curDigit+1, favNum, favNumCountSoFar + 1, nonFavNum, nonFavNumCountSoFar,maxDigit);
        else
            res += f_less(curDigit+1, favNum, favNumCountSoFar, i, (i==nonFavNum?nonFavNumCountSoFar+1:1),maxDigit);
    return res;
}

并通过0到9调用所有数字:

long long res = 0;
for(int maxDigit = 1; maxDigit < NUMBER_OF_DIGITS(N); ++maxDigit)
    for(int favNumber = 0; favNumber < 10; ++favNumber)
        res += f_less(0, favNumber, 0, -1, 0, maxDigit);

第四步:

最后我们必须计算f_equal。这里我们必须将数字保存在一个字符串中,以便始终检查我们是否仍然在递归函数中的N以下范围内。这是f_equal的实现(再次使用memoization或自下而上):

string s = NUM_TO_STRING(N);
int maxDigit = s.size();
long long f_equal(int curDigit, int favNum, int favNumCountSoFar,int nonFavNum, int nonFavNumCountSoFar, bool isEqual){ //isEqual checks that whether our number is equal to N or it's lesser than it 
    if(curDigit == maxDigit ){
        //for numbers with even maxDigit there may be a case when we have 2 favorite numbers
        //and we should count them only once. like 522552
        if(favNumCountSoFar*2 == maxDigit && favNumCountSoFar == nonFavNumCountSoFar) return 1;
        if(2*favNumCountSoFar >= maxDigit) return 2;
        return 0;
    }
    long long res = 0;
    for(int i=(curDigit==0?1:0);i<=9;++i){ //skip the leading zero
        if(isEqual && i>(s[curDigit]-'0')) break;
        if(i==favNum)
            res += f_equal(curDigit+1, favNum, favNumCountSoFar + 1, nonFavNum, nonFavNumCountSoFar, isEqual && (i==(s[curDigit]-'0')));
        else
            res += f_equal(curDigit+1, favNum, favNumCountSoFar, i, (i==nonFavNum?nonFavNumCountSoFar+1:1), isEqual && (i==(s[curDigit]-'0')));
    } 
    return res;
}

并称之为:

long long res = 0;
for(int favNumber = 0; favNumber < 10; ++favNumber)
    res += f_equal(0, favNumber,0, -1, 0, true);

最终结果是res/2。代码经过测试并运行良好。

答案 1 :(得分:1)

这是一个部分组合答案。我忽略了如何使用该函数来构建完整的答案。

(请参阅此处了解相同的代码,并提供更详细的评论:https://repl.it/@gl_dbrqn/AllSteelblueJuliabutterfly

将最左边的数字L固定在R右侧L位的数字中,我们可以计算出我们可以分发的方式{{1} }或更多数字(N / 2) by:

Python代码

d

答案 2 :(得分:1)

数字0只是简写。实际上,有无数个前导零和无限数量的尾随零(小数点后),如...000000.000000...

对于所有整数,很明显小数点后至少有0个小数点,因为小数点前面有非零数字;所以可以计算所有整数。

0到1之间有无数个数字;并且所有这些在小数点左边至少有0个,因为它们在小数点后面有非零数字。这同样适用于0到-1之间的数字。

对于计算机可以存储的几乎所有浮点数,根本没有足够的位来抵消所有前导零和尾随零。

唯一无法计算的数字是正无穷大,有些但不是所有非理性数字都是&lt; = 1或&gt; = -1。

代码:

float getCount(int x, int y) {
    if(x == y) return 0.0; // Special case (no numbers are between x and y)
    return INFINITY;       // The closest value to the correct answer that a computer can use
}