Bir tamsayı N verildi. N'den büyük ve en küçük tamsayı, rakam olarak 0 veya 1 olan tek sayı nedir?


15

Ben bir tamsayı N var. 0 veya 1 dışında herhangi bir rakam içermeyen N'den büyük en küçük tamsayıyı bulmalıyım. Örneğin: Eğer N = 12öyleyse cevap 100. C ++ 'da kaba kuvvet yaklaşımını kodladım.

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;
        }
    }
}

Sorun şu ki, yaklaşımım çok yavaş. Bunu çözmek için çok verimli bir yaklaşım olduğuna inanıyorum. Bu sorunu nasıl verimli bir şekilde çözebilirim?


4
Birimlerle başlayın. Rakam 0 veya 1
dışındaysa

1
Bu benzer bir problemi tarif eder. Belki yardımcı olur
TomBombadil

Negatifliğe Nizin veriliyor mu? Ayrıca, türünüzü taşma riski nedeniyle bu zordur. Sınırlar neler N?
Bathsheba

1
@SembeiNorimaki: bu yanlış. Sadece 0 ve 1'den oluşan bir sayı değiştirmeden bırakılacak.
Yves Daoust

1
@SembeiNorimaki: Başka arızalar olduğunu söyledim. Yönteminiz yanlış olduğu için kalırlar. 1'den 50'ye kadar olan tam sayıları deneyin ve hatalar bulacaksınız. Errare humanum, perseverare diabolicum.
Yves Daoust

Yanıtlar:


20
  1. Artım N,

  2. Soldan başlayarak, yukarıdaki 1'den bir rakam bulana kadar tarayın. Kısmi sayıyı ondan önce artırın ve geri kalanını sıfırlayın.

Örneğin

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
...

Kanıt:

İstenen sayı en az N + 1 olmalıdır, bu yüzden artarız. Şimdi daha büyük veya eşit bir sayı arıyoruz.

Bize diyelim önek başlangıç 0/1 rakam ve ekini sonra ne. Son ekin ilk basamağını sıfırla değiştirmeli ve daha büyük bir önek ayarlamalıyız. Uygun en küçük önek, geçerli önek artı bir önektir. Ve en küçük ekin tümü sıfırdır.


Güncelleme:

Ön ekin ikili sayı olarak artırılması gerektiğini belirtmeyi unuttum , aksi takdirde yasaklanmış rakamlar görünebilir.


7

Başka bir olasılık şu olabilir:

  • Kullanılan veri türü tarafından desteklenen en büyük ondalık sayı olan "1111111 ... 1111" ile başlıyorsunuz

    Algoritma, girdinin bu sayıdan daha küçük olduğunu varsayar; aksi takdirde başka bir veri türü kullanmanız gerekir.

    Örnek: Kullanırken long longnumarayla başlarsınız 1111111111111111111.

  • Ardından her ondalık basamağı soldan sağa doğru işleyin:
    • Rakamı 1'den 0'a değiştirmeyi deneyin.
    • Sonuç hala girişinizden daha büyükse değişikliği yapın (rakamı 0 olarak değiştirin).
    • Aksi takdirde rakam 1 olarak kalır.

Misal

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

Doğruluk kanıtı:

Bu algoritmada basamak basamak işliyoruz. Her adımda, değeri zaten bilinen rakamlar ve henüz değerleri bilinmeyen rakamlar vardır.

Her adımda, en soldaki bilinmeyen basamağı araştırıyoruz.

Bu rakamı "0" ve diğer tüm bilinmeyen rakamları "1" olarak ayarladık. Problanacak basamak bilinmeyen basamakların en önemlisi olduğundan, elde edilen sayı mümkün olan en büyük sayıdır ve bu rakam "0" dır. Bu sayı girişten daha az veya eşitse, incelenen basamak bir "1" olmalıdır.

Öte yandan, elde edilen sayı, incelenen rakamın "1" olduğu tüm olası rakamlardan daha küçüktür. Ortaya çıkan sayı girişten büyükse, rakam "0" olmalıdır.

Bu, her adımda bir basamak hesaplayabileceğimiz anlamına gelir.

C kodu

(C kodu C ++ altında da çalışmalıdır):

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

Birkaç alternatif önereyim.

I. Artan. @Yvesdaoust yönteminin bir değişikliği olarak düşünün.

  1. N'yi 1 arttır
  2. Başında sıfır bulunan sonucu genişlet

  3. 2'den küçükse sondan ikinci basamağa (a) gidin, sonra her şeyi olduğu gibi bırakın
    (b) aksi takdirde 0'a ayarlayın ve önceki değeri artırın
  4. 3a, b adımlarını tekrarlayın

Örnekler:

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

Ondalık biçimde sonuç alırsınız.


II. Bölme.

  1. N'yi 1 arttır
  2. Toplamı 0 olarak ayarla
  3. Div (D) ve mod (M) parçalarını almak için sonucu 10'a bölün
  4. M
    (a) 'yı M 1'i aşarsa kontrol edin, ardından D
    (b)' yi artırın aksi takdirde toplamı M * 10 k arttırın ; burada k, geçerli yineleme sayısıdır (0 ile başlayan)
  5. D 0 olana kadar 3,4. Adımları tekrarlayın.

Örnek 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

Örnek 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

Örnek 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

Örnek 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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.