Cho một số nguyên N. Số nguyên nhỏ nhất lớn hơn N chỉ có 0 hoặc 1 là các chữ số của nó là gì?


15

Tôi có một số nguyên N. Tôi phải tìm số nguyên nhỏ nhất lớn hơn N không chứa bất kỳ chữ số nào khác 0 hoặc 1. Ví dụ: Nếu N = 12sau đó câu trả lời là 100. Tôi đã mã hóa một cách tiếp cận vũ phu trong 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;
        }
    }
}

Vấn đề là, cách tiếp cận của tôi quá chậm. Tôi tin rằng có một cách tiếp cận rất hiệu quả để giải quyết điều này. Làm thế nào tôi có thể giải quyết vấn đề này một cách hiệu quả?


4
Bắt đầu với các đơn vị. Nếu chữ số khác 0 hoặc 1, hãy đặt số 0 và mang 1. Lặp lại cho mỗi vị trí
Sembei Norimaki

1
Điều này mô tả một vấn đề tương tự. Có thể giúp
TomBombadil

Là tiêu cực Nđược phép? Ngoài ra, điều này là khó khăn khi bạn có nguy cơ tràn loại của bạn. Giới hạn trên là Ngì?
Bathsheba

1
@SembeiNorimaki: điều này là sai. Nó sẽ không thay đổi một số chỉ gồm 0 và 1. Và có những thất bại khác.
Yves Daoust

1
@SembeiNorimaki: Tôi đã nói rằng có những thất bại khác. Họ vẫn còn, như phương pháp của bạn là sai. Hãy thử các số nguyên từ 1 đến 50 và bạn sẽ tìm thấy sai lầm. Errare humanum, perseverare diabolicum.
Yves Daoust

Câu trả lời:


20
  1. Tăng N,

  2. Bắt đầu từ bên trái, quét cho đến khi bạn tìm thấy một chữ số ở trên 1. Tăng số phần trước nó và không có phần còn lại.

Ví dụ

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

Bằng chứng:

Số được yêu cầu phải có ít nhất N + 1, đây là lý do tại sao chúng tôi tăng. Chúng tôi đang tìm kiếm một số lớn hơn hoặc bằng.

Chúng ta hãy gọi tiền tố là các chữ số 0/1 ban đầu và hậu tố xuất hiện sau. Chúng ta phải thay thế chữ số đầu tiên của hậu tố bằng 0 và đặt tiền tố lớn hơn. Tiền tố nhỏ nhất phù hợp là tiền tố hiện tại cộng với một tiền tố. Và hậu tố nhỏ nhất phù hợp là tất cả các số không.


Cập nhật:

Tôi quên xác định rằng tiền tố phải được tăng lên dưới dạng số nhị phân , nếu không các chữ số bị cấm có thể xuất hiện.


7

Một khả năng khác sẽ là một trong những điều sau đây:

  • Bạn bắt đầu với số thập phân lớn nhất của loại "1111111 ... 1111" được hỗ trợ bởi loại dữ liệu được sử dụng

    Thuật toán giả định rằng đầu vào nhỏ hơn số này; nếu không, bạn sẽ phải sử dụng một loại dữ liệu khác.

    Ví dụ: Khi sử dụng long long, bạn bắt đầu với số 1111111111111111111.

  • Sau đó xử lý từng chữ số thập phân từ trái sang phải:
    • Cố gắng thay đổi chữ số từ 1 thành 0.
    • Nếu kết quả vẫn lớn hơn đầu vào của bạn, hãy thực hiện thay đổi (thay đổi chữ số thành 0).
    • Nếu không, chữ số vẫn là 1.

Thí dụ

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

Bằng chứng về sự đúng đắn:

Chúng tôi xử lý chữ số bằng chữ số trong thuật toán này. Trong mỗi bước, có những chữ số có giá trị đã được biết và chữ số chưa biết giá trị.

Trong mỗi bước, chúng tôi thăm dò chữ số ngoài cùng bên trái.

Chúng tôi đặt chữ số đó thành "0" và tất cả các chữ số không xác định khác thành "1". Bởi vì chữ số được thăm dò là số có nghĩa nhất trong số các chữ số chưa biết, số kết quả là số lớn nhất có thể có với chữ số đó là "0". Nếu số này nhỏ hơn hoặc bằng đầu vào, chữ số được thăm dò phải là "1".

Mặt khác, số kết quả nhỏ hơn tất cả các số có thể có trong đó chữ số được thăm dò là "1". Nếu số kết quả lớn hơn đầu vào, chữ số phải là "0".

Điều này có nghĩa là chúng ta có thể tính toán một chữ số trong mỗi bước.

Mã C

(Mã C cũng hoạt động theo 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

Hãy để tôi đề nghị một vài lựa chọn thay thế.

I. Tăng dần. Hãy coi đó là một sửa đổi của phương pháp @YvesDaoust.

  1. Tăng N lên 1
  2. Mở rộng kết quả với số 0 đứng đầu
  3. Đi từ chữ số cuối cùng đến chữ số thứ hai
    (a) nếu nó nhỏ hơn 2 thì để mọi thứ như
    (b) nếu không thì đặt nó thành 0 và tăng trước
  4. Lặp lại các bước 3a, b

Ví dụ:

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

Bạn nhận được kết quả ở định dạng thập phân.


II. Chia rẽ.

  1. Tăng N lên 1
  2. Đặt tổng thành 0
  3. Chia kết quả cho 10 để có các phần div (D) và mod (M)
  4. Kiểm tra M
    (a) nếu M vượt quá 1 thì tăng D
    (b) nếu không tăng tổng bằng M * 10 k , trong đó k là số lần lặp hiện tại (bắt đầu bằng 0)
  5. Lặp lại các bước 3,4 cho đến khi D bằng 0

Ví dụ 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

Ví dụ 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

Ví dụ 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

Ví dụ 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.