Chuyển đổi chuỗi thành số nguyên mà không cần sử dụng phép nhân C #


9

Có cách nào để chuyển đổi chuỗi thành số nguyên mà không cần sử dụng Phép nhân. Việc thực hiện int.Pude () cũng sử dụng phép nhân. Tôi có những câu hỏi tương tự khác, nơi bạn có thể chuyển đổi chuỗi thành int theo cách thủ công, nhưng điều đó cũng đòi hỏi phải lấy số theo cơ sở của nó 10. Đây là một câu hỏi phỏng vấn tôi có trong một cuộc phỏng vấn và dường như tôi không thể tìm thấy câu trả lời nào về vấn đề này.


3
có (văn bản) hay không có (tiêu đề)?
hủy

2
Bạn có thể làm rõ? Tiêu đề của bạn nói 'không' sử dụng trong khi văn bản của bạn nói 'với' bằng cách sử dụng ...
vonludi

1
Xem xét phần còn lại của nội dung câu hỏi (ví dụ: "nhưng điều đó cũng đòi hỏi nhân số với cơ sở 10"), tiêu đề là chính xác. Thêm vào đó, nếu phép nhân được cho phép thì điều này là không quan trọng, vì vậy sẽ không có ý nghĩa gì khi hỏi nó.
John

7
bài viết này đề nghị thay thế phép nhân bằng mười lần thay đổi bit và phép cộng ( x<<1 + x<<3), nhưng đây vẫn là một cách sử dụng phép nhân, vì vậy thật khó để nói liệu đó có phải là "theo tinh thần" của câu hỏi không ...
Simon MᶜKenzie

3
for (int i = 0; i < 10; i++) result += number;tính không?
cant7

Câu trả lời:


12

Nếu bạn giả sử một hệ thống số cơ sở 10 và thay thế phép nhân bằng cách dịch chuyển bit ( xem tại đây ) thì đây có thể là một giải pháp cho các số nguyên dương .

public int StringToInteger(string value)
{
    int number = 0;
    foreach (var character in value)
        number = (number << 1) + (number << 3) + (character - '0');

    return number;
}

Xem ví dụ về ideone .

Giả định duy nhất là các nhân vật '0'để '9'nằm trực tiếp bên cạnh nhau trong bộ ký tự. Các ký tự chữ số được chuyển đổi thành giá trị nguyên của chúng bằng cách sử dụng character - '0'.

Biên tập:

Đối với số nguyên âm phiên bản này ( xem tại đây ) hoạt động.

public static int StringToInteger(string value)
{
    bool negative = false;
    int i = 0;

    if (value[0] == '-')
    {
        negative = true;
        ++i;
    }

    int number = 0;
    for (; i < value.Length; ++i)
    {
        var character = value[i];
        number = (number << 1) + (number << 3) + (character - '0');
    }

    if (negative)
        number = -number;
    return number;
}

Nói chung, bạn nên đưa lỗi vào tài khoản như kiểm tra null, các vấn đề với các ký tự không phải số khác, v.v.


6

Nó phụ thuộc. Chúng ta đang nói về hoạt động logic của phép nhân, hay nó thực sự được thực hiện như thế nào trong phần cứng?

Ví dụ: bạn có thể chuyển đổi một chuỗi thập lục phân (hoặc bát phân hoặc bất kỳ chuỗi hai số cơ sở nào khác) thành một số nguyên "không nhân". Bạn có thể đi theo từng ký tự và giữ oring ( |) và bitshifting ( <<). Điều này tránh sử dụng *toán tử.

Làm tương tự với các chuỗi thập phân là khó hơn, nhưng chúng ta vẫn có phép cộng đơn giản. Bạn có thể sử dụng các vòng lặp với sự bổ sung để làm điều tương tự. Khá đơn giản để làm. Hoặc bạn có thể tạo "bảng nhân" của riêng mình - hy vọng bạn đã học được cách nhân số trong trường; bạn có thể làm điều tương tự với một máy tính. Và tất nhiên, nếu bạn đang sử dụng máy tính thập phân (chứ không phải nhị phân), bạn có thể thực hiện "bitshift", giống như với chuỗi thập lục phân trước đó. Ngay cả với một máy tính nhị phân, bạn có thể sử dụng một loạt các bithifts - (a << 1) + (a << 3)cũng giống như a * 2 + a * 8 == a * 10. Cẩn thận về số âm. Bạn có thể tìm ra nhiều thủ thuật để làm cho điều này thú vị.

Tất nhiên, cả hai điều này chỉ là sự nhân lên trong ngụy trang. Đó là bởi vì các hệ thống số vị trí vốn đã được nhân lên . Đó là cách biểu diễn số cụ thể đó hoạt động. Bạn có thể có các đơn giản hóa để che giấu sự thật này (ví dụ: số nhị phân chỉ cần 01vì vậy thay vì nhân, bạn có thể có một điều kiện đơn giản - tất nhiên, những gì bạn thực sự làm vẫn là nhân, chỉ với hai đầu vào có thể và hai có thể đầu ra), nhưng nó luôn ở đó, ẩn nấp. <<là giống như * 2, ngay cả khi phần cứng thực hiện thao tác có thể đơn giản hơn và / hoặc nhanh hơn.

Để loại bỏ hoàn toàn phép nhân, bạn cần tránh sử dụng hệ thống định vị. Ví dụ, chữ số La Mã là phụ gia (lưu ý rằng chữ số La Mã thực tế không sử dụng các quy tắc compact hóa chúng ta có ngày hôm nay - Bốn sẽ là IIII, không IV, và nó mười bốn tuổi có thể được viết bằng bất kỳ hình thức như XIIII, IIIIX, IIXII, VVIIIIvv). Chuyển đổi một chuỗi như vậy thành số nguyên trở nên rất dễ dàng - chỉ cần đi từng ký tự và tiếp tục thêm. Nếu nhân vật là X, thêm mười. Nếu V, thêm năm. NếuI, cộng một. Tôi hy vọng bạn có thể thấy tại sao chữ số La Mã vẫn phổ biến từ rất lâu; hệ thống số vị trí là tuyệt vời khi bạn cần phải thực hiện nhiều phép nhân và chia. Nếu bạn chủ yếu xử lý phép cộng và phép trừ, chữ số La Mã hoạt động rất tốt và đòi hỏi ít đi học hơn (và bàn tính dễ thực hiện và sử dụng hơn nhiều so với máy tính định vị!).

Với những bài tập như thế này, có rất nhiều điều thú vị và bỏ lỡ về những gì người phỏng vấn thực sự mong đợi. Có lẽ họ chỉ muốn xem quá trình suy nghĩ của bạn. Bạn có nắm bắt được kỹ thuật ( <<không thực sự nhân lên)? Bạn có biết lý thuyết số và khoa học máy tính? Bạn chỉ cần lao vào với mã của bạn, hoặc yêu cầu làm rõ? Bạn có thấy đó là một thử thách thú vị, hay một câu hỏi phỏng vấn nhàm chán vô lý khác không liên quan đến công việc của bạn là gì không? Chúng tôi không thể nói cho bạn câu trả lời mà người phỏng vấn đang tìm kiếm.

Nhưng tôi hy vọng tôi ít nhất đã cho bạn một cái nhìn thoáng qua về các câu trả lời có thể :)


Nếu chúng tôi sử dụng hệ thống chữ số La Mã, bạn sẽ thêm như thế nào nếu chúng tôi có các ký tự như B, T, S, R, G, A, v.v. không phải là một phần của hệ thống chữ số La Mã. Nói cách khác, làm thế nào để có được một int tương đương?
Adheesh

@Adheesh Tôi không biết bạn đang cố gắng hỏi về điều gì. Bạn có thể đưa ra một ví dụ về những gì bạn nghĩ sẽ là một vấn đề?
Luaan

Giả sử chúng ta có một chuỗi "12345" và chúng ta muốn chuyển đổi nó thành một int. Điều gì xảy ra nếu tôi không muốn sử dụng hệ thống số vị trí và thay vào đó sử dụng hệ thống số La Mã. Làm thế nào chúng ta có thể làm điều đó? (Tôi hoàn toàn không muốn sử dụng phép nhân)
Adheesh

@Adheesh Trong hệ thống chữ số La Mã, chuỗi sẽ không phải là "12345". Đó là toàn bộ vấn đề. Hệ thống số vị trí vốn đã được nhân. Hệ thống chữ số La Mã là phụ gia. Chuỗi roman sẽ giống như "MMMMMMMMMMMMCCCXXXXIIIII". Đi từng nhân vật, và tiếp tục thêm số.
Luaan

@Adheesh Tất nhiên, trong thực tế thực tế, nó sẽ không phải là một mớ hỗn độn khó sử dụng lâu như vậy. Thay vì "12345 mét", bạn sẽ nói một cái gì đó như "mét XII kilo và CCCXXXXIIIII" hoặc đại loại như vậy. Các hệ thống đo lường cũ được điều chỉnh cho những người không thể đếm được nhiều - chỉ cần so sánh phạm vi giá trị bạn có thể đại diện với các đơn vị đế quốc với các đơn vị hiện đại nếu bạn chỉ có thể đếm đến mười hai :)
Luaan

5

Xem xét nó là một câu hỏi phỏng vấn, hiệu suất có thể không phải là một ưu tiên cao. Tại sao không chỉ:

private int StringToInt(string value)
{
    for (int i = int.MinValue; i <= int.MaxValue; i++)
        if (i.ToString() == value)
            return i;
    return 0; // All code paths must return a value.
}

Nếu chuỗi đã truyền không phải là số nguyên, phương thức sẽ đưa ra một ngoại lệ tràn.


1
Rực rỡ: P Chỉ cần đảm bảo rằng bạn không sử dụng nó nếu không có phản hồi ngay lập tức từ người phỏng vấn: DI tưởng tượng thậm chí có thể có cách cải thiện hiệu suất với các phần khớp, sử dụng cùng một phương pháp cơ bản. Ít nhất, một kiểm tra đơn giản cho các số âm giúp bạn tiết kiệm một nửa vòng lặp; một kiểm tra cho lẻ / thậm chí một nửa khác.
Luaan

@Luaan Tôi muốn làm điều đó với ít dòng nhất có thể :) ...public int StringToInt(string value, int search_from = int.MinValue) => value == search_from.ToString() ? search_from : StringToInt (value, ++search_from);
nl-x

Đáng buồn thay, điều đó sẽ bùng nổ: D Nhưng đó là một giải pháp tuyệt vời để viết mã trên giấy - nó làm cho nó rất rõ ràng chính xác và rất khó để viết sai. Bạn cũng có thể sử dụng LIINQ - Enumerable.Range(int.MinValue, int.MaxValue).First(i => i.ToString() == stringValue.
Luaan

0

Bất kỳ phép nhân có thể được thay thế bằng phép cộng lặp lại. Vì vậy, bạn có thể thay thế bất kỳ bội số nào trong thuật toán hiện có bằng phiên bản chỉ sử dụng phép cộng:

static int Multiply(int a, int b)
{
    bool isNegative = a > 0 ^ b > 0;
    int aPositive = Math.Abs(a);
    int bPositive = Math.Abs(b);
    int result = 0;
    for(int i = 0; i < aPositive; ++i)
    {
        result += bPositive;
    }
    if (isNegative) {
        result = -result;
    }
    return result;
}

Bạn có thể đi xa hơn và viết một Chuỗi chuyên dụng cho Int bằng cách sử dụng ý tưởng này nhằm giảm thiểu số lượng bổ sung (số âm và xử lý lỗi được bỏ qua cho ngắn gọn):

static int StringToInt(string v)
{
    const int BASE = 10;
    int result = 0;
    int currentBase = 1;
    for (int digitIndex = v.Length - 1; digitIndex >= 0; --digitIndex)
    {
        int digitValue = (int)Char.GetNumericValue(v[digitIndex]);
        int accum = 0;
        for (int i = 0; i < BASE; ++i)
        {
            if (i == digitValue)
            {
                result += accum;
            }
            accum += currentBase;
        }
        currentBase = accum;
    }
    return result;
}

Nhưng tôi không nghĩ đó là vấn đề đáng giá vì hiệu suất dường như không phải là mối quan tâm ở đây.

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.