การแปลงสตริงเป็นจำนวนเต็มโดยไม่ต้องใช้การคูณ C #


9

มีวิธีการแปลงสตริงเป็นจำนวนเต็มโดยไม่ต้องใช้การคูณ การใช้งาน int.Parse () ยังใช้การคูณ ฉันมีคำถามที่คล้ายกันอื่น ๆ ที่คุณสามารถแปลงสตริงเป็น int ได้ด้วยตนเอง แต่นั่นก็ต้องใช้จำนวนที่ผิดโดยฐานที่ 10 นี่เป็นคำถามสัมภาษณ์ที่ฉันมีในการสัมภาษณ์ครั้งหนึ่งและฉันไม่สามารถหาคำตอบเกี่ยวกับเรื่องนี้


3
ด้วย (ข้อความ) หรือไม่มี (ชื่อ)?
d4zed

2
คุณช่วยอธิบายได้ไหม ชื่อของคุณพูดว่า 'ไม่ใช้' ในขณะที่ข้อความของคุณพูดว่า "กับ" กำลังใช้ ...
vonludi

1
เมื่อพิจารณาเนื้อหาส่วนที่เหลือของคำถาม (เช่น "แต่ต้องมีการคูณจำนวนด้วยฐาน 10") ชื่อถูกต้อง นอกจากนี้หากอนุญาตให้คูณได้สิ่งนี้จะเล็กน้อยดังนั้นจึงไม่มีเหตุผลที่จะถาม
จอห์

7
บทความนี้แสดงให้เห็นการเปลี่ยนคูณสิบกับบิตกะและนอกจาก ( x<<1 + x<<3) แต่ก็ยังคงเป็นวิธีการใช้คูณดังนั้นจึงเป็นเรื่องยากที่จะบอกได้ว่าที่ "จิตวิญญาณ" ของคำถาม ...
ไซมอนMᶜKenzie

3
ไม่for (int i = 0; i < 10; i++) result += number;นับ?
canton7

คำตอบ:


12

หากคุณสมมติฐาน-10 ระบบตัวเลขแทนการคูณโดยกะบิต ( ดูที่นี่ ) นี้สามารถแก้ปัญหาสำหรับจำนวนเต็มบวก

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

    return number;
}

ดูตัวอย่างในideone

ข้อสันนิษฐานเพียงอย่างเดียวคือตัวละครที่'0'จะ'9'นอนถัดจากกันและกันในชุดตัวละคร character - '0'ตัวละครหลักจะถูกแปลงเป็นค่าจำนวนเต็มของตนโดยใช้

แก้ไข:

สำหรับจำนวนเต็มลบรุ่นนี้ ( ดูที่นี่ ) ใช้งานได้

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

โดยทั่วไปคุณควรคำนึงถึงข้อผิดพลาดเช่นการตรวจสอบโมฆะปัญหาเกี่ยวกับตัวละครอื่น ๆ ที่ไม่ใช่ตัวเลขเป็นต้น


6

มันขึ้นอยู่กับ. เรากำลังพูดถึงการดำเนินการเชิงตรรกะของการคูณหรือวิธีการทำในฮาร์ดแวร์จริง ๆ ?

ตัวอย่างเช่นคุณสามารถแปลงสตริงเลขฐานสิบหก (หรือฐานแปดหรือตัวคูณฐานสองตัวอื่น) เป็นจำนวนเต็ม "โดยไม่ต้องคูณ" คุณสามารถไปตัวละครโดยตัวละครและให้ oring ( |) และ bitshifting ( <<) วิธีนี้หลีกเลี่ยงการใช้*โอเปอเรเตอร์

การทำเช่นเดียวกันกับสตริงทศนิยมนั้นยากกว่า แต่เราก็ยังมีวิธีง่าย ๆ คุณสามารถใช้ลูปได้นอกจากนี้เพื่อทำสิ่งเดียวกัน สวยง่ายน่าสนใจ หรือคุณสามารถสร้าง "ตารางสูตรคูณ" ของคุณเอง - หวังว่าคุณจะได้เรียนรู้วิธีการคูณตัวเลขในโรงเรียน คุณสามารถทำสิ่งเดียวกันกับคอมพิวเตอร์ และแน่นอนถ้าคุณใช้คอมพิวเตอร์ทศนิยม (แทนที่จะเป็นไบนารี่) คุณสามารถทำ "bitshift" ได้เหมือนกับสตริงเลขฐานสิบหกที่ก่อนหน้านี้ ถึงแม้จะมีเครื่องคอมพิวเตอร์ไบนารีคุณสามารถใช้ชุดของ bitshifts - การเป็นเช่นเดียวกับ(a << 1) + (a << 3) a * 2 + a * 8 == a * 10ระมัดระวังเกี่ยวกับตัวเลขลบ คุณสามารถหาเทคนิคมากมายเพื่อทำให้สิ่งนี้น่าสนใจ

แน่นอนว่าทั้งสองอย่างนี้เป็นเพียงการเพิ่มการปลอมตัว นั่นเป็นเพราะระบบตัวเลขตำแหน่งที่มีการคูณโดยเนื้อแท้ นั่นเป็นวิธีที่การแสดงตัวเลขโดยเฉพาะนั้นทำงานได้ คุณสามารถมีการทำให้เข้าใจง่ายที่ซ่อนความจริงนี้ (เช่นต้องการเลขฐานสองเท่านั้น0และ1ดังนั้นแทนที่จะมีการคูณคุณสามารถมีเงื่อนไขง่ายๆ - แน่นอนสิ่งที่คุณกำลังทำจริง ๆ ยังคงเป็นการคูณเพียงแค่อินพุตที่เป็นไปได้สองอันเท่านั้น เอาท์พุท) แต่มันอยู่ที่นั่นเสมอที่ซุ่มซ่อน <<เหมือนกับ* 2แม้ว่าฮาร์ดแวร์ที่ใช้ในการดำเนินการจะง่ายขึ้นและ / หรือเร็วขึ้น

หากต้องการกำจัดการคูณทั้งหมดคุณต้องหลีกเลี่ยงการใช้ระบบตำแหน่ง ยกตัวอย่างเช่นเลขโรมันเป็นสารเติมแต่ง (ทราบว่าเลขโรมันที่เกิดขึ้นจริงไม่ได้ใช้กฎ compactification ที่เรามีวันนี้ - สี่จะIIIIไม่ได้IVและมันสิบสี่อาจจะเขียนในรูปแบบใด ๆ เช่นXIIII, IIIIX, IIXII, VVIIIIฯลฯ ) การแปลงสตริงเป็นจำนวนเต็มกลายเป็นเรื่องง่ายมากเพียงไปที่ตัวอักษรต่ออักขระและเพิ่มต่อไป ถ้าตัวละครเป็นXเพิ่มสิบ ถ้าVเพิ่มอีกห้า ถ้าIเพิ่มหนึ่งรายการ ฉันหวังว่าคุณจะเห็นว่าทำไมตัวเลขโรมันยังคงเป็นที่นิยมมานาน ระบบตัวเลขตำแหน่งยอดเยี่ยมเมื่อคุณต้องการคูณและหารจำนวนมาก หากคุณต้องการจัดการกับการบวกและการลบตัวเลขโรมันนั้นใช้งานได้ดีและต้องการการศึกษาน้อยกว่ามาก (และลูกคิดนั้นง่ายกว่ามากในการสร้างและใช้งานมากกว่าเครื่องคิดเลขตำแหน่ง!)

ด้วยการมอบหมายเช่นนี้มีจำนวนมากและพลาดเกี่ยวกับสิ่งที่ผู้สัมภาษณ์คาดหวังจริง บางทีพวกเขาอาจต้องการเห็นกระบวนการคิดของคุณ คุณโอบกอด technicalities ( <<ไม่ได้คูณจริงๆ )? คุณรู้ทฤษฎีจำนวนและวิทยาการคอมพิวเตอร์หรือไม่ คุณเพียงแค่กระโดดด้วยรหัสของคุณหรือขอคำชี้แจง? คุณเห็นว่ามันเป็นความท้าทายที่สนุกหรือเป็นคำถามสัมภาษณ์ที่น่าเบื่อที่ไร้สาระอื่น ๆ ที่ไม่เกี่ยวข้องกับงานของคุณหรือไม่? เป็นไปไม่ได้ที่เราจะบอกคำตอบที่ผู้สัมภาษณ์กำลังมองหา

แต่ฉันหวังว่าอย่างน้อยฉันก็ให้คำตอบที่เป็นไปได้ :)


ถ้าเราใช้ระบบเลขโรมันคุณจะเพิ่มอย่างไรถ้าเรามีตัวละครเช่น B, T, S, R, G, A ฯลฯ ซึ่งไม่ได้เป็นส่วนหนึ่งของระบบเลขโรมัน กล่าวอีกนัยหนึ่งจะได้ค่าที่เทียบเท่ากันได้อย่างไร
Adheesh

@ Adheesh ฉันไม่รู้ว่าคุณกำลังพยายามถามอะไร คุณยกตัวอย่างสิ่งที่คุณคิดว่าเป็นปัญหาหรือไม่
Luaan

สมมติว่าเรามีสตริง "12345" และเราต้องการแปลงเป็น int จะทำอย่างไรถ้าฉันไม่ต้องการใช้ระบบตัวเลขตำแหน่งและใช้ระบบตัวเลขแบบโรมันแทน เราจะทำอย่างไร (ฉันไม่ต้องการใช้การคูณเลย)
Adheesh

@Adheesh ในระบบเลขโรมันสตริงจะไม่เป็น "12345" นั่นคือประเด็นทั้งหมด ระบบตัวเลขเชิงตำแหน่งมีหลายระดับ ระบบเลขโรมันเป็นสารเติมแต่ง สตริงโรมันจะเป็นสิ่งที่ "MMMMMMMMMMMMCCCXXXXIIIII" ไปตัวอักษรทีละตัวและเพิ่มตัวเลข
Luaan

@ Adheesh แน่นอนในความเป็นจริงในทางปฏิบัติจริงมันจะไม่เป็นระเบียบยาวเทอะทะ แทนที่จะเป็น "12345 เมตร" คุณจะพูดอะไรเช่น "สิบสองกิโลและ CCCXXXXIIIII เมตร" หรือเช่นนั้น ระบบการวัดแบบเก่าได้รับการปรับให้เหมาะกับคนที่ไม่สามารถนับได้มากเพียงเปรียบเทียบช่วงของค่าที่คุณสามารถนำเสนอด้วยหน่วยของจักรวรรดิกับหน่วยที่ทันสมัยหากคุณสามารถนับได้ถึงสิบสอง :)
Luaan

5

เมื่อพิจารณาว่าเป็นคำถามสัมภาษณ์ประสิทธิภาพอาจไม่ได้รับความสำคัญสูง ทำไมไม่เพียงแค่:

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

ถ้าสตริงที่ส่งไม่ใช่จำนวนเต็มเมธอดจะส่งข้อยกเว้นโอเวอร์โฟลว์


1
ยอดเยี่ยม: P ตรวจสอบให้แน่ใจว่าคุณไม่ได้ใช้ถ้าไม่มีข้อเสนอแนะจากผู้สัมภาษณ์ทันที: DI ลองคิดว่าอาจมีวิธีในการปรับปรุงประสิทธิภาพด้วยการจับคู่บางส่วนโดยใช้วิธีการพื้นฐานแบบเดียวกัน อย่างน้อยที่สุดการตรวจสอบจำนวนลบอย่างง่ายช่วยให้คุณประหยัดครึ่งวง ตรวจสอบคี่ / ครึ่งอีก
Luaan

@ Luaan ฉันต้องการที่จะทำมันในบรรทัดเล็กที่สุดเท่าที่เป็นไปได้ :) ...public int StringToInt(string value, int search_from = int.MinValue) => value == search_from.ToString() ? search_from : StringToInt (value, ++search_from);
nl-x

น่าเศร้าที่จะเกิดการระเบิด: D แต่มันเป็นทางออกที่ดีสำหรับการเขียนโค้ดลงบนกระดาษ - มันทำให้ถูกต้องชัดเจนมากและยากที่จะเขียนผิด นอกจากนี้คุณยังสามารถใช้ LIINQ Enumerable.Range(int.MinValue, int.MaxValue).First(i => i.ToString() == stringValue-
Luaan

0

การคูณใด ๆ สามารถแทนที่ด้วยการเพิ่มซ้ำ ดังนั้นคุณสามารถแทนที่การคูณใด ๆ ในอัลกอริทึมที่มีอยู่ด้วยเวอร์ชันที่ใช้การเพิ่มเท่านั้น:

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

คุณสามารถไปต่อและเขียน String พิเศษเพื่อ Int โดยใช้ความคิดนี้ซึ่งช่วยลดจำนวนของการเพิ่ม (ลดจำนวนลบและการจัดการข้อผิดพลาดเพื่อความกะทัดรัด):

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

แต่ฉันไม่คิดว่ามันจะคุ้มค่ากับปัญหาเพราะประสิทธิภาพดูเหมือนจะไม่เป็นปัญหาที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.