0Pricing
Coding Interview Prep · บทเรียน

การเรียงแบบเร็วและการเลือกหมุด

สร้างการเรียงแบบเร็วด้วยรูปแบบแบ่งส่วนของ Lomuto และ Hoare อภิปรายกรณีเลวร้ายสุด O(n²) และวิธีที่การเลือกหมุดแบบสุ่มช่วยลดปัญหานี้

การเรียงแบบเร็วและการเลือกหมุด เป็นบทเรียน Coding Interview Prep ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Coding Interview Prep และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Coding Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน

การเรียงลำดับแบบเร็ว: การแบ่งแล้วพิชิตภายในพื้นที่เดิม

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

def quick_sort(arr, lo=0, hi=None):
    if hi is None: hi = len(arr) - 1
    if lo < hi:
        pivot_idx = partition(arr, lo, hi)
        quick_sort(arr, lo, pivot_idx - 1)  # sort left
        quick_sort(arr, pivot_idx + 1, hi)  # sort right

def partition(arr, lo, hi):
    pivot = arr[hi]  # Lomuto: choose last element as pivot
    i = lo - 1
    for j in range(lo, hi):
        if arr[j] <= pivot:
            i += 1
            arr[i], arr[j] = arr[j], arr[i]
    arr[i+1], arr[hi] = arr[hi], arr[i+1]
    return i + 1

arr = [3, 6, 8, 10, 1, 2, 1]
quick_sort(arr)
print(arr)  # [1, 1, 2, 3, 6, 8, 10]

รูปแบบการแบ่งส่วนของโลมูโต

การแบ่งส่วนแบบโลมูโตใช้สมาชิกตัวสุดท้ายเป็นจุดหมุน ตัวชี้ช้า i จะติดตามขอบเขตของบริเวณ 「น้อยกว่าจุดหมุน」 ส่วนตัวชี้เร็ว j จะสแกนไปข้างหน้า เมื่อ arr[j] <= pivot ให้เพิ่มค่า i แล้วสลับ arr[i] กับ arr[j] เพื่อขยายบริเวณสมาชิกขนาดเล็ก หลังจากสแกนเสร็จ ให้วางจุดหมุนไว้ที่ i+1 ด้วยการสลับกับ arr[hi] วิธีนี้ใช้งานง่าย แต่ทำการสลับมากกว่ารูปแบบของฮอร์ถึง 3 เท่า

def lomuto_partition_traced(arr, lo, hi):
    pivot = arr[hi]
    i = lo - 1
    print(f'Pivot: {pivot}, array: {arr[lo:hi+1]}')
    for j in range(lo, hi):
        if arr[j] <= pivot:
            i += 1
            arr[i], arr[j] = arr[j], arr[i]
    arr[i+1], arr[hi] = arr[hi], arr[i+1]
    print(f'After partition: {arr[lo:hi+1]}')
    return i + 1

arr = [3, 1, 4, 1, 5, 9, 2, 6]
lomuto_partition_traced(arr, 0, len(arr)-1)

รูปแบบการแบ่งส่วนของฮอร์

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

def hoare_partition(arr, lo, hi):
    pivot = arr[lo]  # first element as pivot
    i, j = lo - 1, hi + 1
    while True:
        i += 1
        while arr[i] < pivot: i += 1
        j -= 1
        while arr[j] > pivot: j -= 1
        if i >= j: return j
        arr[i], arr[j] = arr[j], arr[i]

def quick_sort_hoare(arr, lo=0, hi=None):
    if hi is None: hi = len(arr) - 1
    if lo < hi:
        p = hoare_partition(arr, lo, hi)
        quick_sort_hoare(arr, lo, p)      # note: p not p-1
        quick_sort_hoare(arr, p+1, hi)

arr = [3, 6, 8, 10, 1, 2, 1]
quick_sort_hoare(arr)
print(arr)  # [1, 1, 2, 3, 6, 8, 10]

กรณีแย่ที่สุด O(n²): อินพุตที่เรียงลำดับอยู่แล้ว

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

import sys
sys.setrecursionlimit(5000)

def quick_sort_naive(arr, lo=0, hi=None):
    if hi is None: hi = len(arr) - 1
    comparisons = [0]
    def _qs(lo, hi):
        if lo >= hi: return
        pivot = arr[hi]  # last element pivot
        i = lo - 1
        for j in range(lo, hi):
            comparisons[0] += 1
            if arr[j] <= pivot:
                i += 1; arr[i], arr[j] = arr[j], arr[i]
        arr[i+1], arr[hi] = arr[hi], arr[i+1]
        p = i + 1
        _qs(lo, p-1); _qs(p+1, hi)
    _qs(lo, hi)
    return comparisons[0]

import math
n = 100
sorted_arr = list(range(n))
ops = quick_sort_naive(sorted_arr)
print(f'n={n}, ops={ops}, n^2={n**2}')  # ops close to n*(n-1)/2

จุดหมุนแบบสุ่ม: คาดว่าจะใช้เวลา O(n log n)

การเลือกจุดหมุนแบบสุ่มอย่างสม่ำเสมอ (สลับสมาชิกสุ่มกับ arr[hi] ก่อนการแบ่งส่วน) จะทำให้ความน่าจะเป็นที่จะเลือกจุดหมุนที่แย่อย่างต่อเนื่องลดลงแบบเอ็กซ์โพเนนเชียล จำนวนครั้งที่คาดว่าจะเปรียบเทียบคือ 2n ln(n) ≈ 1.39 n log₂(n) จึงได้ เวลาที่คาดว่าจะเป็น O(n log n) ด้วยความน่าจะเป็นที่สูงมาก นี่คือเหตุผลที่การเรียงลำดับแบบเร็วโดยใช้การสุ่มถูกนำไปใช้จริง เพราะช่วยหลีกเลี่ยงกรณีแย่ที่สุดที่ผิดปกติซึ่งผู้ไม่หวังดีอาจสร้างขึ้นเพื่อโจมตีกลยุทธ์ที่ใช้จุดหมุนตายตัว

import random

def quick_sort_random(arr, lo=0, hi=None):
    if hi is None: hi = len(arr) - 1
    if lo < hi:
        # Randomise pivot
        rand_i = random.randint(lo, hi)
        arr[rand_i], arr[hi] = arr[hi], arr[rand_i]
        # Lomuto partition with last element as pivot
        pivot = arr[hi]
        i = lo - 1
        for j in range(lo, hi):
            if arr[j] <= pivot:
                i += 1; arr[i], arr[j] = arr[j], arr[i]
        arr[i+1], arr[hi] = arr[hi], arr[i+1]
        p = i + 1
        quick_sort_random(arr, lo, p - 1)
        quick_sort_random(arr, p + 1, hi)

arr = list(range(100, 0, -1))  # worst case for naive
quick_sort_random(arr)
print(arr[:10])  # [1,2,3,4,5,6,7,8,9,10]

จุดหมุนค่ามัธยฐานของสามค่า

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

def median_of_three(arr, lo, hi):
    mid = (lo + hi) // 2
    # Sort lo, mid, hi values in place
    if arr[lo] > arr[mid]:  arr[lo], arr[mid] = arr[mid], arr[lo]
    if arr[lo] > arr[hi]:   arr[lo], arr[hi]  = arr[hi],  arr[lo]
    if arr[mid] > arr[hi]:  arr[mid], arr[hi] = arr[hi],  arr[mid]
    # Median is now at arr[mid]; swap to arr[hi-1] as pivot
    arr[mid], arr[hi] = arr[hi], arr[mid]
    return arr[hi]  # pivot value

arr = [3, 9, 1]
print(median_of_three(arr, 0, 2), arr)  # 3, [1,3,9] (sorted)

ธงชาติเนเธอร์แลนด์: การแบ่งส่วนสามทาง

การแบ่งส่วนมาตรฐานจะวางสมาชิกที่น้อยกว่าจุดหมุนไว้ทางซ้ายและสมาชิกที่มากกว่าไว้ทางขวา แต่สมาชิกที่เท่ากับจุดหมุนจะกระจัดกระจายอยู่ การแบ่งส่วนสามทาง (ธงชาติเนเธอร์แลนด์) จะสร้างสามบริเวณ ได้แก่ <จุดหมุน, ==จุดหมุน และ >จุดหมุน วิธีนี้สำคัญอย่างยิ่งสำหรับอาร์เรย์ที่มีค่าซ้ำกันจำนวนมาก เพราะการเรียงลำดับแบบเร็วมาตรฐานจะเสื่อมลงเป็น O(n²) แต่การเรียงลำดับแบบเร็วสามทางจะใช้เวลา O(n) เมื่ออินพุตมีค่าเดียวกันทั้งหมด

def three_way_partition(arr, lo, hi):
    pivot = arr[lo]
    lt = lo      # arr[lo..lt-1] < pivot
    gt = hi      # arr[gt+1..hi] > pivot
    i = lo       # current
    while i <= gt:
        if arr[i] < pivot:
            arr[lt], arr[i] = arr[i], arr[lt]
            lt += 1; i += 1
        elif arr[i] > pivot:
            arr[i], arr[gt] = arr[gt], arr[i]
            gt -= 1  # don't advance i
        else:
            i += 1
    return lt, gt  # pivot occupies arr[lt..gt]

arr = [3, 1, 4, 1, 5, 9, 2, 6, 3, 3]
lt, gt = three_way_partition(arr, 0, len(arr)-1)
print(arr, '| pivot region:', lt, 'to', gt)

Quickselect: ค่าที่น้อยที่สุดลำดับที่ k ใน O(n)

Quickselectใช้ขั้นตอนการแบ่งส่วนของการเรียงลำดับแบบเร็วเพื่อค้นหาสมาชิกที่มีค่าน้อยที่สุดลำดับที่ k ในเวลาเฉลี่ย O(n) โดยไม่ต้องเรียงลำดับทั้งหมด หลังการแบ่งส่วน จุดหมุนจะอยู่ในตำแหน่งสุดท้าย p หาก p == k ให้คืนค่า arr[p] หาก k < p ให้เรียกซ้ำกับส่วนที่แบ่งด้านซ้าย หาก k > p ให้เรียกซ้ำกับส่วนที่แบ่งด้านขวา โดยเฉลี่ย การเรียกซ้ำแต่ละครั้งจะแบ่งปัญหาออกเป็นครึ่งหนึ่ง: O(n) + O(n/2) + O(n/4) + ... = O(2n) = O(n)

import random

def quickselect(nums, k):
    '''Find kth smallest (0-indexed) in O(n) average.'''
    def _select(lo, hi):
        if lo == hi: return nums[lo]
        rand_i = random.randint(lo, hi)
        nums[rand_i], nums[hi] = nums[hi], nums[rand_i]
        pivot = nums[hi]
        i = lo - 1
        for j in range(lo, hi):
            if nums[j] <= pivot:
                i += 1; nums[i], nums[j] = nums[j], nums[i]
        p = i + 1
        nums[p], nums[hi] = nums[hi], nums[p]
        if p == k:    return nums[p]
        elif k < p:   return _select(lo, p - 1)
        else:         return _select(p + 1, hi)
    return _select(0, len(nums) - 1)

print(quickselect([3,2,1,5,6,4], 1))  # 2  (2nd smallest)

ความซับซ้อนด้านพื้นที่ของการเรียงลำดับแบบเร็ว

การเรียงลำดับแบบเร็วเรียกว่า 「ทำงานภายในพื้นที่เดิม」 แต่ยังใช้พื้นที่สแตกเฉลี่ย O(log n) สำหรับการเรียกซ้ำ (หนึ่งเฟรมต่อหนึ่งระดับของต้นไม้การเรียกซ้ำ) ในกรณีแย่ที่สุด ความลึกของสแตกจะเป็น O(n) หากต้องการรับประกันว่าพื้นที่สแตกในกรณีแย่ที่สุดเป็น O(log n) ให้เรียกซ้ำกับส่วนที่ เล็กกว่า ก่อนเสมอ และใช้การปรับการเรียกท้ายให้เหมาะสมกับส่วนที่ใหญ่กว่า ขีดจำกัดการเรียกซ้ำของไพธอนทำให้การเรียกซ้ำของการเรียงลำดับแบบเร็วที่ลึกมากมีความเสี่ยง ซึ่งควรกล่าวถึงในการสัมภาษณ์

def quick_sort_optimised(arr, lo=0, hi=None):
    if hi is None: hi = len(arr) - 1
    while lo < hi:
        p = lomuto_partition_qs(arr, lo, hi)
        # Recurse on smaller partition; iterate on larger
        if p - lo < hi - p:
            quick_sort_optimised(arr, lo, p - 1)
            lo = p + 1  # tail-call elimination
        else:
            quick_sort_optimised(arr, p + 1, hi)
            hi = p - 1

def lomuto_partition_qs(arr, lo, hi):
    pivot = arr[hi]; i = lo - 1
    for j in range(lo, hi):
        if arr[j] <= pivot: i += 1; arr[i], arr[j] = arr[j], arr[i]
    arr[i+1], arr[hi] = arr[hi], arr[i+1]
    return i + 1

การเปรียบเทียบอัลกอริทึมการเรียงลำดับ

สังเคราะห์ความรู้ของคุณ:

  • การเรียงลำดับแบบเร็ว: คาดว่าจะเป็น O(n log n), กรณีแย่ที่สุด O(n²), ใช้พื้นที่ O(log n), ไม่เสถียร และเร็วที่สุดในทางปฏิบัติสำหรับข้อมูลสุ่ม
  • การเรียงลำดับแบบผสาน: รับประกัน O(n log n), ใช้พื้นที่ O(n), มีความเสถียร และเหมาะที่สุดสำหรับรายการเชื่อมโยงกับการเรียงลำดับภายนอก
  • การเรียงลำดับแบบฮีพ: รับประกัน O(n log n), ใช้พื้นที่ O(1), ไม่เสถียร และช้ากว่าในทางปฏิบัติเนื่องจากการพลาดแคช
  • การเรียงลำดับแบบแทรก: กรณีดีที่สุดเป็น O(n) เหมาะอย่างยิ่งสำหรับ n ขนาดเล็กหรือข้อมูลที่เกือบเรียงลำดับแล้ว
ในการสัมภาษณ์ ให้เลือกวิธีโดยอธิบายจากข้อแลกเปลี่ยนเหล่านี้

# Python's sorted() uses Timsort:
# - Hybrid: merge sort for large runs, insertion sort for small (< 64 elements)
# - Stable, O(n log n) worst case
# - O(n) best case for sorted/reverse-sorted/nearly-sorted
# - O(n) extra space

import random
arr = random.sample(range(10000), 1000)
sorted_arr = sorted(arr)  # Timsort
print(sorted_arr[:5], '...')  # first 5 elements

Introsort: การผสานทั้งสามวิธี

Introsort (ใช้ใน C++ STL std::sort) ผสานการเรียงลำดับแบบเร็ว การเรียงลำดับแบบฮีพ และการเรียงลำดับแบบแทรกเข้าด้วยกัน โดยเริ่มจากการเรียงลำดับแบบเร็วโดยใช้การสุ่ม หากความลึกของการเรียกซ้ำเกิน 2 log n (บ่งชี้ว่าลำดับจุดหมุนไม่ดี) ให้เปลี่ยนไปใช้การเรียงลำดับแบบฮีพเพื่อรับประกัน O(n log n) และใช้การเรียงลำดับแบบแทรกกับอาร์เรย์ย่อยที่มีขนาดเล็กกว่า 16 สมาชิก วิธีนี้ให้กรณีแย่ที่สุดเป็น O(n log n) พร้อมความเร็วกรณีเฉลี่ยของการเรียงลำดับแบบเร็วและประสิทธิภาพของการเรียงลำดับแบบแทรกสำหรับอาร์เรย์ย่อยขนาดเล็ก

# Introsort hybrid (simplified)
def introsort(arr, depth_limit=None):
    if depth_limit is None:
        import math
        depth_limit = 2 * int(math.log2(len(arr) + 1)) if arr else 0
    if len(arr) <= 16:
        # insertion sort for small arrays
        for i in range(1, len(arr)):
            key = arr[i]; j = i - 1
            while j >= 0 and arr[j] > key:
                arr[j+1] = arr[j]; j -= 1
            arr[j+1] = key
        return arr
    if depth_limit == 0:
        arr.sort()  # fall back to heapsort equivalent
        return arr
    # Otherwise quick sort
    pivot = arr[-1]
    small = [x for x in arr[:-1] if x <= pivot]
    large = [x for x in arr[:-1] if x > pivot]
    return introsort(small, depth_limit-1) + [pivot] + introsort(large, depth_limit-1)

print(introsort([5,3,8,1,9,2,7]))

แบบทดสอบสั้น ๆ

ทดสอบความเข้าใจแนวคิดโครงสร้างข้อมูลและอัลกอริทึม — การเตรียมตัวสัมภาษณ์การเขียนโค้ดจากบทเรียนนี้

ทบทวนบทเรียน

ในบทเรียนนี้ คุณได้เรียนรู้ว่า: การเรียงลำดับแบบเร็วแบ่งส่วนภายในพื้นที่เดิมรอบจุดหมุนและเรียกซ้ำกับแต่ละฝั่ง ทำให้มีเวลาที่คาดว่าจะเป็น O(n log n) และใช้พื้นที่สแตก O(log n) ซึ่งในทางปฏิบัติเร็วกว่าการเรียงลำดับแบบผสานสำหรับข้อมูลสุ่ม กรณีแย่ที่สุด O(n²) เกิดขึ้นกับอินพุตที่เรียงลำดับแล้วเมื่อใช้จุดหมุนตายตัว และหลีกเลี่ยงได้ด้วยการเลือกจุดหมุนแบบสุ่มหรือค่ามัธยฐานของสามค่า และ การแบ่งส่วนสามทางจัดการสมาชิกที่ซ้ำกันได้อย่างมีประสิทธิภาพ ขณะที่ Quickselect ขยายแนวคิดการแบ่งส่วนเพื่อค้นหาสมาชิกที่มีค่าน้อยที่สุดลำดับที่ k ในเวลาเฉลี่ย O(n) โดยไม่ต้องเรียงลำดับทั้งหมด บทถัดไปเราจะสำรวจการเรียงลำดับที่ไม่ใช้การเปรียบเทียบและ sort ในตัวของไพธอน

คำถามที่พบบ่อย

บทเรียน “การเรียงแบบเร็วและการเลือกหมุด” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การเรียงแบบเร็วและการเลือกหมุด” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Coding Interview Prep ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Coding Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การเรียงแบบเร็วและการเลือกหมุด”

สร้างการเรียงแบบเร็วด้วยรูปแบบแบ่งส่วนของ Lomuto และ Hoare อภิปรายกรณีเลวร้ายสุด O(n²) และวิธีที่การเลือกหมุดแบบสุ่มช่วยลดปัญหานี้ คุณปฏิบัติ Coding Interview Prep ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Coding Interview Prep หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Coding Interview Prep บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “การเรียงแบบเร็วและการเลือกหมุด” ใช้เวลานานแค่ไหน

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

ฉันเขียนและรันโค้ดในบทเรียน Coding Interview Prep นี้ได้ไหม

ได้ บทเรียน Coding Interview Prep ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การเรียงแบบฟองและการเรียงแบบแทรก
  2. การเรียงแบบผสาน: แบ่ง เรียง ผสาน
  3. การเรียงแบบเร็วและการเลือกหมุด
  4. การเรียงที่ไม่เปรียบเทียบและ sort() ของ Python
← กลับไปที่ Coding Interview Prep