Konvertieren von Zeichenfolgen in Ganzzahlen ohne Verwendung von Multiplikation C #

9

Gibt es eine Möglichkeit, Zeichenfolgen ohne Verwendung der Multiplikation in Ganzzahlen umzuwandeln? Die Implementierung von int.Parse () verwendet ebenfalls die Multiplikation. Ich habe andere ähnliche Fragen, bei denen Sie einen String manuell in int konvertieren können, aber dazu muss auch die Zahl durch die Basis 10 multipliziert werden. Dies war eine Interviewfrage, die ich in einem der Interviews hatte, und ich kann keine Antwort darauf finden.

chaudrhy
quelle
3
mit (Text) oder ohne (Titel)?
d4zed
2
Könnten Sie das klarstellen? Ihr Titel sagt "ohne" mit, während Ihr Text "mit" mit ...
vonludi
1
In Anbetracht des restlichen Inhalts der Frage (z. B. "aber dazu muss auch die Zahl mit der Basis 10 multipliziert werden") ist der Titel korrekt. Wenn eine Multiplikation zulässig ist, ist dies trivial, sodass es keinen Sinn macht, danach zu fragen.
John
7
In diesem Artikel wird vorgeschlagen , die Multiplikation durch zehn durch Bitverschiebungen und Addition ( x<<1 + x<<3) zu ersetzen , aber es ist immer noch eine Möglichkeit, die Multiplikation zu verwenden.
Daher ist
3
Zählt das for (int i = 0; i < 10; i++) result += number;?
Kanton7

Antworten:

12

Wenn Sie ein Basis-10-Zahlensystem annehmen und die Multiplikation durch Bitverschiebungen ersetzen ( siehe hier ), kann dies eine Lösung für positive ganze Zahlen sein .

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

    return number;
}

Siehe das Beispiel auf ideone .

Die einzige Voraussetzung ist , dass die Zeichen '0'zu '9'einander in dem Zeichensatz unmittelbar nächsten liegen. Die Ziffernzeichen werden mit in ihren ganzzahligen Wert konvertiert character - '0'.

Bearbeiten:

Für negative ganze Zahlen funktioniert diese Version ( siehe hier ).

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

Im Allgemeinen sollten Sie Fehler wie Nullprüfungen, Probleme mit anderen nicht numerischen Zeichen usw. berücksichtigen.

Andre Kampling
quelle
6

Es hängt davon ab, ob. Sprechen wir über die logische Operation der Multiplikation oder wie es tatsächlich in der Hardware gemacht wird?

Beispielsweise können Sie eine hexadezimale (oder oktale oder eine andere Basis-Zwei-Multiplikator-Zeichenfolge) in eine Ganzzahl "ohne Multiplikation" konvertieren. Sie können Zeichen für Zeichen gehen und oring ( |) und bitshifting ( <<) beibehalten . Dies vermeidet die Verwendung des *Operators.

Dasselbe mit Dezimalzeichenfolgen zu tun ist schwieriger, aber wir haben immer noch eine einfache Addition. Sie können zusätzlich Schleifen verwenden, um dasselbe zu tun. Ziemlich einfach zu machen. Oder Sie können Ihre eigene "Multiplikationstabelle" erstellen - hoffentlich haben Sie in der Schule gelernt, wie man Zahlen multipliziert; Sie können dasselbe mit einem Computer tun. Und natürlich können Sie, wenn Sie sich auf einem Dezimalcomputer befinden (und nicht auf einem Binärcomputer), die "Bitverschiebung" ausführen, genau wie bei der früheren hexadezimalen Zeichenfolge. Selbst mit einem Binärcomputer können Sie eine Reihe von Bitverschiebungen verwenden - (a << 1) + (a << 3)das gleiche wie a * 2 + a * 8 == a * 10. Vorsicht bei negativen Zahlen. Sie können viele Tricks herausfinden, um dies interessant zu machen.

Natürlich sind beide nur Multiplikation in Verkleidung. Das liegt daran, dass positionelle numerische Systeme von Natur aus multiplikativ sind . So funktioniert diese spezielle numerische Darstellung. Sie können Vereinfachungen haben, die diese Tatsache verbergen (z. B. müssen nur Binärzahlen verwendet werden, 0und 1anstatt zu multiplizieren, können Sie eine einfache Bedingung haben - natürlich ist das, was Sie wirklich tun, immer noch Multiplikation, nur mit nur zwei möglichen Eingaben und zwei möglichen Ausgänge), aber es ist immer da und lauert. <<ist das gleiche wie * 2, selbst wenn die Hardware, die den Vorgang ausführt, einfacher und / oder schneller sein kann.

Um die Multiplikation vollständig zu beseitigen, müssen Sie die Verwendung eines Positionssystems vermeiden. Zum Beispiel sind römische Ziffern Additiv (beachten Sie, dass tatsächliche römische Ziffern nicht die kompaktere Regeln verwendet haben wir heute haben - vier wären IIII, nicht IV, und es vierzehn könnte wie in irgendeiner Form geschrieben werden XIIII, IIIIX, IIXII, VVIIIIetc.). Das Konvertieren einer solchen Zeichenfolge in eine Ganzzahl wird sehr einfach - gehen Sie einfach Zeichen für Zeichen und fügen Sie weitere hinzu. Wenn das Zeichen ist X, addieren Sie zehn. Wenn V, fügen Sie fünf hinzu. WennI, füge eins hinzu. Ich hoffe, Sie können sehen, warum römische Ziffern so lange beliebt blieben. Positionsnumerische Systeme sind wunderbar, wenn Sie viel multiplizieren und dividieren müssen. Wenn Sie sich hauptsächlich mit Addition und Subtraktion beschäftigen, funktionieren römische Ziffern hervorragend und erfordern viel weniger Schulbildung (und ein Abakus ist viel einfacher herzustellen und zu verwenden als ein Positionsrechner!).

Bei solchen Aufgaben gibt es eine Menge Erfolg und Misserfolg darüber, was der Interviewer tatsächlich erwartet. Vielleicht wollen sie nur Ihre Denkprozesse sehen. Akzeptieren Sie technische Aspekte ( <<ist nicht wirklich Multiplikation)? Kennen Sie Zahlentheorie und Informatik? Tauchen Sie einfach in Ihren Code ein oder bitten Sie um Klarstellung? Sehen Sie es als eine lustige Herausforderung oder als eine weitere lächerliche, langweilige Interviewfrage, die für Ihren Job keine Relevanz hat? Es ist uns unmöglich, Ihnen die Antwort zu sagen, nach der der Interviewer gesucht hat.

Aber ich hoffe ich habe dir wenigstens einen Einblick in mögliche Antworten gegeben :)

Luaan
quelle
Wenn wir das römische Zahlensystem verwenden, wie würden Sie hinzufügen, wenn wir Zeichen wie B, T, S, R, G, A usw. hätten, die nicht Teil des römischen Zahlensystems sind. Mit anderen Worten, wie würde man ein int-Äquivalent erhalten?
Adheesh
@Adheesh Ich habe keine Ahnung, worüber du fragen willst. Können Sie ein Beispiel geben, was Ihrer Meinung nach ein Problem wäre?
Luaan
Angenommen, wir haben eine Zeichenfolge "12345" und möchten sie in eine int konvertieren. Was ist, wenn ich nicht das Positionsnummernsystem und stattdessen das römische Zahlensystem verwenden möchte? Wie könnten wir das machen? (Ich möchte überhaupt keine Multiplikation verwenden)
Adheesh
@Adheesh In einem römischen Zahlensystem wäre die Zeichenfolge nicht "12345". Das ist der springende Punkt. Positionsnumerische Systeme sind von Natur aus multiplikativ. Das römische Zahlensystem ist additiv. Die römische Zeichenfolge wäre so etwas wie "MMMMMMMMMMMMCCCXXXXIIIII". Gehen Sie Zeichen für Zeichen und fügen Sie weitere Zahlen hinzu.
Luaan
@Adheesh Natürlich wäre es in der Praxis kein so langes, unhandliches Durcheinander. Anstelle von "12345 Meter" würden Sie so etwas wie "XII Kilo und CCCXXXXIIIII Meter" oder so sagen. Alte Messsysteme wurden an Menschen angepasst, die nicht viel zählen konnten - vergleichen Sie einfach den Wertebereich, den Sie mit imperialen Einheiten darstellen können, mit modernen Einheiten, wenn Sie nur bis zwölf zählen können :)
Luaan
5

Da es sich um eine Interviewfrage handelt, hat die Leistung möglicherweise keine hohe Priorität. Warum nicht einfach:

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

Wenn die übergebene Zeichenfolge keine Ganzzahl ist, löst die Methode eine Überlaufausnahme aus.

nl-x
quelle
1
Genial: P Stellen Sie nur sicher, dass Sie es nicht verwenden, wenn der Interviewer kein unmittelbares Feedback gibt: DI Stellen Sie sich vor, es könnte sogar Möglichkeiten geben, die Leistung mit Teilübereinstimmungen zu verbessern, indem Sie denselben grundlegenden Ansatz verwenden. Zumindest erspart Ihnen eine einfache Überprüfung auf negative Zahlen die halbe Schleife. ein Scheck für ungerade / gerade noch eine Hälfte.
Luaan
@Luaan Ich wollte es in so kleinen Zeilen wie möglich machen :) ...public int StringToInt(string value, int search_from = int.MinValue) => value == search_from.ToString() ? search_from : StringToInt (value, ++search_from);
nl-x
Leider wird das explodieren: D Aber es ist eine großartige Lösung, um den Code auf Papier zu schreiben - es macht ihn ganz offensichtlich richtig und es ist schwer, falsch zu schreiben. Sie können auch LIINQ - verwenden Enumerable.Range(int.MinValue, int.MaxValue).First(i => i.ToString() == stringValue.
Luaan
0

Jede Multiplikation kann durch wiederholte Addition ersetzt werden. Sie können also jede Multiplikation in einem vorhandenen Algorithmus durch eine Version ersetzen, die nur Addition verwendet:

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

Sie könnten noch weiter gehen und mit dieser Idee einen speziellen String an Int schreiben, der die Anzahl der Hinzufügungen minimiert (negative Anzahl und Fehlerbehandlung der Kürze halber weggelassen):

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

Aber ich denke nicht, dass sich die Mühe lohnt, da die Leistung hier kein Problem zu sein scheint.

David Brown
quelle