วิธีการค้นหาองค์ประกอบกลางของรายการที่เชื่อมโยงในหนึ่งผ่าน?


12

หนึ่งในคำถามยอดนิยมจากโครงสร้างข้อมูลและอัลกอริทึมส่วนใหญ่ถามในการสัมภาษณ์ทางโทรศัพท์


5
หากคำตอบที่ปรากฏในกระทู้นี้เป็นสิ่งที่ผู้สัมภาษณ์คาดหวังไว้คำถามนี้จะไม่ทดสอบความสามารถทางเทคนิค แต่ผู้สมัครสามารถหลบได้เหมือนทนายความ
G. Bach

2
นี่เป็นคำถามสัมภาษณ์ที่แย่มากเพราะมันเป็นช่วงวิกฤตของคำว่า " pass " ซึ่งคลุมเครือคลุมเครือและเป็นอัตนัย คำตอบที่ดีเกือบทั้งหมดสำหรับคำถามนี้เกี่ยวข้องกับการใช้คำจำกัดความที่ไม่เหมาะสมเพื่อให้คุณสามารถเพิกเฉยได้
RBarryYoung

2
คำถามก็ทำให้เกิดการถกเถียงกันมากมายที่นี่ นั่นหมายความว่าเป็นคำถามสัมภาษณ์ที่ดีในแง่หนึ่ง: มันเริ่มต้นที่คุณคิด
Hendrik Jan

3
ฉันต้องการที่จะตอบว่า "อ่านองค์ประกอบทั้งหมดเป็นเวกเตอร์จากนั้นเข้าถึงองค์ประกอบที่ขนาดตำแหน่ง () / 2"
Cort Ammon

1
@HendrikJan ที่จริงฉันคิดว่ามันเป็นคำถามสัมภาษณ์ที่แย่มาก ก่อนมีแนวโน้มที่จะนำไปสู่ข้อโต้แย้งเกี่ยวกับความหมายของ "ในรอบเดียว" มากกว่าการอภิปรายที่มีประสิทธิผล ประการที่สองผู้สมัครสามารถหาคำตอบที่ "ถูกต้อง" แล้วปฏิเสธเพราะพวกเขาคิดว่าละเมิดหลักเกณฑ์ "ในครั้งเดียว" ข้อที่สามเนื่องจากเป็นคำถามที่รู้จักกันดีมันเป็นการทดสอบที่ดีกว่าของ "คุณรู้จักคำถามสัมภาษณ์ยอดนิยมหรือไม่" กว่า "คุณเหมาะสมกับงานนี้หรือไม่" หนึ่งในนั้นควรเพียงพอที่จะตอบคำถามนี้ ทั้งสามพร้อมกันเป็นหายนะ
David Richerby

คำตอบ:


24

โดยการโกงและทำสองผ่านในเวลาเดียวกันในแบบคู่ขนาน แต่ฉันไม่รู้ว่านายหน้าจะเป็นแบบนี้หรือไม่

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


1
ใช่มันไม่ชัดเจนว่านี่เป็นผ่านเดียว คำถามไม่ชัดเจนในจุดนั้น
David Richerby

2
โดยวิธีการนี้จะเกี่ยวข้องกับปริศนาที่คุณมีสองเทียนหนึ่งชั่วโมงในการเผาไหม้แต่ละและคุณจะถูกขอให้วัด 45 นาที
Hendrik Jan

2
สิ่งนี้แตกต่างกันจริง ๆ แล้ววนซ้ำรายการนับองค์ประกอบแล้ววนซ้ำเป็นครั้งที่สองไปยังจุดครึ่งทาง? สิ่งที่แตกต่างคือเมื่อคุณย้ำครึ่งพิเศษ @RBarryYoung กล่าวถึงคำตอบอื่น ๆ ที่คล้ายกันจริง ๆ มันไม่ได้เป็นการผ่านครั้งเดียวมันเป็นการผ่านไปครึ่ง

2
หากรายการมีความยาวการย้ายทั้งสองตัวชี้ "พร้อมกัน" จะทำให้เกิดการพลาดแคชน้อยกว่าการวนซ้ำตั้งแต่ต้นครั้งที่สอง
zwol

2
วิธีนี้ใช้หลักการเดียวกับเต่าและอัลกอริทึมกระต่ายสำหรับการตรวจจับรอบ
Joshua Taylor

7

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

ทางออกที่เรียบง่ายและไร้สาระเกือบเป็นเพียงการเพิ่มโหนดกลางทุกสองโหนด

function middle(start) {
    var middle = start
    var nextnode = start
    var do_increment = false;
    while (nextnode.next != null) {
        if (do_increment) {
             middle = middle.next;
        }
        do_increment = !do_increment;
        nextnode = nextnode.next;
    }
    return middle;
}

ตัวเลือกที่สองของคุณคือคำตอบที่ถูกต้อง (แน่นอน IMHO)
Matthew Crumley

1
มันทำให้ 1 1/2 ผ่านรายการที่เชื่อมโยง
RBarryYoung

6

อธิบายอย่างละเอียดเกี่ยวกับคำตอบของ Hendrik

หากเป็นรายการที่เชื่อมโยงเป็นสองเท่าให้ทำซ้ำจากปลายทั้งสองด้าน

function middle(start, end) {
  do_advance_start = false;
  while(start !== end && start && end) {
     if (do_advance_start) {
        start = start.next
     }
     else {
        end = end.prev
     }
     do_advance_start = !do_advance_start
  }
  return (start === end) ? start : null;
}

ป.ร. ให้ไว้ [1, 2, 3] => 2

1, 3
1, 2
2, 2

ป.ร. ให้ไว้ [1, 2] => 1

1, 2
1, 1

ป.ร. ให้ไว้ [1] => 1

ป.ร. ให้ไว้ [] => null


สิ่งนี้มีประสิทธิภาพเพียงใด? คุณกำลังทำซ้ำ n ครั้งและไม่ใช่ n / 2
Karan Khanna

3

สร้างโครงสร้างที่มีตัวชี้ที่สามารถชี้ไปยังโหนดของรายการที่เชื่อมโยงและมีตัวแปรจำนวนเต็มซึ่งเก็บจำนวนของโหนดในรายการ

struct LL{
    struct node *ptr;
    int         count;
}start;

start.ptrstart.count=1
start.count

start.count


-2

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

นี่คือโค้ด Java บางส่วนที่ทำให้เกิดประเด็น (แม้ว่าแนวคิดของอาเรย์แบบไดนามิกจะดูสับสนเล็กน้อย) ฉันจะให้ C / C ++ แต่ฉันเป็นสนิมในพื้นที่นั้น

public Node getMiddleNode(List<Node> nodes){

    int size = 1;
    //add code to dynamically increase size if at capacity after adding
    Node[] pointers = new Node[10];

    for (int i = 0; i < nodes.size(); i++){
        //remember to dynamically allocate more space if needed
        pointers[i] = nodes.get(i);
        size++;
    }

    return pointers[(size - 1)/2];

}

-3

การเรียกซ้ำเป็นการพิจารณามากกว่าหนึ่งรอบหรือไม่

สำรวจรายการไปยังจุดสิ้นสุดผ่านการนับจำนวนเต็มโดยการอ้างอิง ทำสำเนาโลคัลของค่านั้นในแต่ละระดับเพื่อการอ้างอิงในภายหลังและเพิ่มจำนวนการอ้างอิงไปยังการโทรครั้งต่อไป

บนโหนดสุดท้ายให้หารจำนวนด้วยสองแล้วตัดทอน / floor () ผลลัพธ์ (หากคุณต้องการให้โหนดแรกเป็น "กลาง" เมื่อมีเพียงสององค์ประกอบเท่านั้น) หรือปัดเศษขึ้น (ถ้าคุณต้องการให้โหนดที่สองเป็น ตรงกลาง"). ใช้ดัชนีที่เป็นศูนย์หรือหนึ่งฐานอย่างเหมาะสม

คลี่คลายให้จับคู่การอ้างอิงกับสำเนาโลคัล (ซึ่งเป็นหมายเลขของโหนด) ถ้าเท่ากับส่งคืนโหนดนั้น มิฉะนั้นส่งคืนโหนดที่ส่งคืนจากการเรียกซ้ำ
.

มีวิธีอื่นในการทำเช่นนี้ บางคนอาจยุ่งยากน้อยกว่า (ฉันคิดว่าฉันเห็นคนพูดว่าอ่านมันลงในอาเรย์และใช้ความยาวของอาเรย์เพื่อกำหนดความรุ่งโรจน์กลาง) แต่ตรงไปตรงมาไม่มีคำตอบที่ดีเพราะเป็นคำถามสัมภาษณ์ที่โง่ หมายเลขหนึ่งที่ยังคงใช้รายการที่เชื่อมโยง ( สนับสนุนความคิดเห็น ); ประการที่สองการค้นหาโหนดกลางเป็นแบบฝึกหัดตามอำเภอใจโดยไม่มีค่าในสถานการณ์จริง สามถ้าฉันต้องการทราบโหนดกลางรายการที่เชื่อมโยงของฉันจะแสดงจำนวนโหนด มันง่ายกว่าที่จะรักษาทรัพย์สินนั้นให้เสียเวลาไปกับการสำรวจรายการทั้งหมดทุกครั้งที่ฉันต้องการโหนดกลาง และสุดท้ายสี่ผู้สัมภาษณ์ทุกคนจะชอบหรือปฏิเสธคำตอบที่ต่างกัน - สิ่งที่ผู้สัมภาษณ์คนหนึ่งคิดว่าลื่นแล้วคนอื่นจะเรียกว่าไร้สาระ

ฉันมักจะตอบคำถามสัมภาษณ์ด้วยคำถามเพิ่มเติม หากฉันได้รับคำถามเช่นนี้ (ฉันไม่เคยมี) ฉันจะถาม (1) คุณเก็บอะไรไว้ในรายการที่เชื่อมโยงนี้และมีโครงสร้างที่เหมาะสมกว่าในการเข้าถึงโหนดกลางได้อย่างมีประสิทธิภาพหากมีความจำเป็นอย่างแท้จริง ; (2) ข้อ จำกัด ของฉันคืออะไร ฉันสามารถทำให้เร็วขึ้นหากหน่วยความจำไม่เป็นปัญหา (เช่นคำตอบของอาร์เรย์) แต่ถ้าผู้สัมภาษณ์คิดว่าการพะรุงพะรังของหน่วยความจำนั้นสิ้นเปลืองฉันจะได้รับผลกระทบ (3) ฉันจะพัฒนาภาษาอะไร เกือบทุกภาษาสมัยใหม่ที่ฉันรู้จักมีคลาสในตัวเพื่อจัดการกับรายการเชื่อมโยงที่ทำให้การข้ามผ่านรายการไม่จำเป็น - ทำไมต้องบูรณาการสิ่งที่ปรับให้มีประสิทธิภาพโดยนักพัฒนาของภาษา


6
คุณไม่ทราบว่าใครลงคะแนนในสิ่งใดดังนั้นข้อสรุปของคุณที่ว่าคนคนหนึ่งที่ลงคะแนนทุกสิ่งอาจหรืออาจไม่จริง แต่แน่นอนไม่มีข้อเท็จจริงพื้นฐานสำหรับคุณ แต่ฉันกำลัง downvoting คำตอบของคุณเพราะเรากำลังมองหาคำอธิบายไม่ใช่กองรหัส
David Richerby

อาจเป็นข้อสันนิษฐาน แต่เมื่อฉันดูสักครู่และน้อยกว่า 30 วินาทีในภายหลังทุกโพสต์จะมี -1 อย่างแน่นอนไม่ใช่โพสที่ไม่สมเหตุสมผล แม้ว่าจะเป็นคนละ 5 หรือ 6 คน แต่ก็ไม่มีใครแสดงความคิดเห็นว่าทำไม แต่ขอขอบคุณอย่างน้อยก็ระบุเหตุผล ฉันไม่เข้าใจว่าทำไมคำอธิบายที่ฟุ่มเฟือยถึงดีกว่ารหัส - ใช่มันเป็นการสัมภาษณ์ทางโทรศัพท์ แต่ฉันไม่ได้ให้คำตอบกับ OP กระป๋องเพื่อสำรอกฉันแสดงให้เขาเห็นวิธีที่จะทำ IE ฉันคิดว่าการโพสต์ข้อความลงเนื่องจากมีโค้ดที่ไม่ถูกเรียกใช้ แต่ขอขอบคุณอย่างน้อยก็บอกว่าทำไมคุณถึงทำเช่นนั้น
James K

จุดยุติธรรม - มันไม่ได้เกิดขึ้นกับฉันที่คุณสามารถรู้เวลาของการลงคะแนน (มีหน้าโหลดในขณะที่พวกเขาเกิดขึ้นคือฉันคิดว่าวิธีเดียวที่ผู้ใช้ทั่วไปอย่างที่เราสามารถหาได้) เรามีคู่ของเมตาโพสต์เกี่ยวกับสาเหตุที่เราพยายามที่จะหลีกเลี่ยงการรหัสที่เกิดขึ้นจริงที่นี่: (1) (2)
David Richerby

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

-5

โดยใช้ 2 พอยน์เตอร์ เพิ่มหนึ่งครั้งในการทำซ้ำแต่ละครั้งและอื่น ๆ ในทุก ๆ รอบที่สอง เมื่อตัวชี้ที่ 1 ชี้ไปที่จุดสิ้นสุดของรายการที่เชื่อมโยงไปที่ตัวชี้ที่ 2 จะชี้ไปที่โหมดตรงกลางของรายการที่เชื่อมโยง


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