给定整数N。大于N且仅以0或1为数字的最小整数是什么?


15

我有一个整数N。我必须找到大于N的最小整数,该整数不包含0或1之外的任何数字。例如:如果N = 12答案为100。我已经用C ++编写了一种蛮力方法。

int main() {
    long long n;
    cin >> n;

    for (long long i = n + 1; ; i++) {
        long long temp = i;
        bool ok = true;
        while (temp != 0) {
            if ( (temp % 10) != 0 && (temp % 10) != 1) {
                ok = false;
                break;
            }
            temp /= 10;
        }
        if (ok == true) {
            cout << i << endl;
            break;
        }
    }
}

问题是,我的方法太慢了。我相信有一个非常有效的方法可以解决这个问题。如何有效解决此问题?


4
从单位开始。如果位数是0或1的其他放用于每个位置的零和携带1.重复
Sembei Norimaki

1
描述了类似的问题。可能有帮助
TomBombadil

否定N允许吗?另外,这很困难,因为您可能会溢出类型。有什么界限N
Bathsheba,

1
@SembeiNorimaki:这是错误的。它将保留一个仅由0和1组成的数字不变。还有其他故障。
伊夫·戴乌斯特

1
@SembeiNorimaki:我说还有其他失败。它们仍然存在,因为您的方法是错误的。尝试从1到50的整数,您会发现错误。Errare humanum,perseverare diabolicum。
伊夫·戴乌斯特

Answers:


20
  1. 增量N

  2. 从左侧开始,进行扫描,直到找到高于1的数字为止。递增部分编号,然后将其剩余部分归零。

例如

12 -> 13 -> 1|3 -> 10|0
101 -> 102 -> 10|2 -> 11|0
109 -> 110 -> 110|
111 -> 112 -> 11|2 -> 100|0
198 -> 199 -> 1|99 -> 10|00
1098 -> 1099 -> 10|99 -> 11|00
10203 -> 10204 -> 10|204 -> 11|000
111234 -> 111235 -> 111|235 -> 1000|000
...

证明:

请求的数字必须至少为N + 1,这就是我们递增的原因。我们现在正在寻找更大或相等的数字。

让我们将前缀称为开头的0/1数字,并在其后添加后缀。我们必须将后缀的第一位替换为零,并设置较大的前缀。合适的最小前缀是当前前缀加1。合适的最小后缀是全零。


更新:

我忘记指定前缀必须作为二进制数递增,否则可能会出现禁止的数字。


7

另一种可能性是以下一种:

  • 您从所使用的数据类型支持的类型为“ 1111111 ... 1111”的最大十进制数开始

    该算法假定输入小于此数字。否则,您将不得不使用其他数据类型。

    示例:使用时long long,请从数字开始1111111111111111111

  • 然后从左到右处理每个十进制数字:
    • 尝试将数字从1更改为0。
    • 如果结果仍然大于输入值,请进行更改(将数字更改为0)。
    • 否则,数字仍为1。

Input = 10103
Start:  111111
Step 1: [1]11111, try [0]11111; 011111 > 10103 => 011111 
Step 2: 0[1]1111, try 0[0]1111; 001111 < 10103 => 011111
Step 3: 01[1]111, try 01[0]111; 010111 > 10103 => 010111
Step 4: 010[1]11, try 010[0]11; 010011 < 10103 => 010111
Step 5: 0101[1]1, try 0101[0]1; 010101 < 10103 => 010111
Step 6: 01011[1], try 01011[0]; 010110 > 10103 => 010110
Result: 010110

正确性证明:

我们在此算法中逐位处理。在每个步骤中,都有其值已知的数字和尚不知道其值的数字。

在每一步中,我们都会探查最左边的未知数字。

我们将该数字设置为“ 0”,并将所有其他未知数字设置为“ 1”。因为要探测的数字是未知数字中的最高位,所以结果数字是最大可能数字,该数字为“ 0”。如果此数字小于或等于输入,则所探测的数字必须为“ 1”。

另一方面,所得到的数字小于要探查的数字为“ 1”的所有可能的数字。如果结果数字大于输入的数字,则该数字必须为“ 0”。

这意味着我们可以在每个步骤中计算一位。

C代码

(C代码也应在C ++下工作):

long long input;
long long result;
long long digit;

... read in input ...

result = 1111111111111111111ll;
digit = 1000000000000000000ll;

while( digit > 0 )
{
    if(result - digit > input)
    {
        result -= digit;
    }
    digit /= 10;
}

... print out output ...

3

让我提出一些替代方案。

I.递增。认为它是@YvesDaoust方法的修改。

  1. N增加1
  2. 以零开头扩展结果
  3. 从最后一位到第二位
    (a)如果小于2,则将所有内容保留为
    (b),否则将其设置为0并增加前
  4. 重复步骤3a,b

例子:

1. N = 0 -> 1 -> (0)|(1) -> 1
2. N = 1 -> 2 -> (0)|(2) -> (1)|(0) -> 10
3. N = 101 -> 102 -> (0)|(1)(0)(2) -> (0)|(1)(1)(0) -> (0)|(1)(1)(0) -> (0)|(1)(1)(0) -> 110
4. N = 298 -> 299 -> (0)|(2)(9)(9) -> (0)|(2)(10)(0) -> (0)|(3)(0)(0) -> (1)|(0)(0)(0) -> 1000

您将获得十进制格式的结果。


二。划分。

  1. N增加1
  2. 将总和设置为0
  3. 将结果除以10得到div(D)和mod(M)零件
  4. 检查M
    (a)如果M超过1,则增加D
    (b),否则增加总和M * 10 k,其中k是当前迭代数(从0开始)
  5. 重复步骤3,4,直到D为0

范例1:

1. N = 0 -> N = 1
2. sum = 0
3. 1/10 -> D == 0, M == 1 -> sum = sum + 1*10^0 == 1
4. D == 0 -> sum == 1

范例2:

1. N = 1 -> N = 2
2. sum = 0
3. 2/10 -> D == 0, M == 2 -> D = D + 1 == 1
4. 1/10 -> D == 0, M == 1 -> sum = sum + 1*10^1 == 10
5. D == 0, sum == 10

范例3:

1. N = 101 -> N = 102
2. sum = 0
3. 102/10 -> D == 10, M == 2 -> D = D + 1 == 11
4. 11/10 -> D == 1, M == 1 -> sum = sum + 1*10^1 = 10
5. 1/10 -> D == 0, M == 1 -> sum = sum + 1*10^2 == 10 + 100 == 110
6. D == 0, sum == 110

范例4:

1. N = 298 -> N = 299
2. sum = 0
3. 299/10 -> D == 29, M == 9 -> D = D + 1 == 30
4. 30/10 -> D == 3, M == 0 -> sum = sum + 0*10^1 == 0
5. 3/10 -> D == 0, M == 3 -> D = D + 1
6. 1/10 -> D == 0, M == 1 -> sum = sum + 1*10^3 == 1000
7. D == 0, sum == 1000
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.