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

สี่เหลี่ยมผืนผ้าที่ใหญ่ที่สุดในฮิสโตแกรม

ใช้สแตกโมโนโทนิกติดตามขอบเขตด้านซ้าย และคำนวณพื้นที่สูงสุดของสี่เหลี่ยมผืนผ้าที่อยู่ภายในฮิสโตแกรมได้ในรอบเดียว

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

ปัญหา: สี่เหลี่ยมผืนผ้าที่ใหญ่ที่สุดในฮิสโตแกรม

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

วิธีตรวจสอบทุกกรณี: สำหรับคู่ (i, j) ทุกคู่ ให้คำนวณความสูงต่ำสุดในช่วง [i, j] แล้วคูณด้วย (j - i + 1) วิธีนี้ใช้เวลา O(n³) หรือ O(n²) หากคำนวณค่าต่ำสุดไว้ล่วงหน้า ซึ่งช้าเกินไป วิธีใช้สแตกแบบโมโนโทนิกทำงานในเวลา O(n)

# Example: heights = [2, 1, 5, 6, 2, 3]
# Rectangles:
# width=1, height=6 at index 3 => area=6
# width=2, height=5 at indices 2-3 => area=10 (maximum!)
# width=6, height=1 across all => area=6
# width=3, height=2 at indices 2-4 => area=6
heights = [2, 1, 5, 6, 2, 3]
print('Heights:', heights)
print('Expected max area: 10 (bars of height 5 and 6, width 2)')

# Brute force for small inputs:
def brute_force(heights):
    n = len(heights)
    max_area = 0
    for i in range(n):
        min_h = heights[i]
        for j in range(i, n):
            min_h = min(min_h, heights[j])
            max_area = max(max_area, min_h * (j - i + 1))
    return max_area

print('Brute force answer:', brute_force(heights))  # 10

แนวคิดสำคัญ: อะไรเป็นตัวจำกัดสี่เหลี่ยมผืนผ้าของแท่งแต่ละแท่ง

สำหรับแท่ง i แต่ละแท่งที่มีความสูง h สี่เหลี่ยมผืนผ้าที่แท่งนั้นสามารถเป็น แท่งที่ต่ำที่สุด ได้จะขยายไปทางซ้ายจนถึงแท่งแรกที่สั้นกว่า h และขยายไปทางขวาจนถึงแท่งแรกที่สั้นกว่า h ความกว้างคือ right_boundary - left_boundary - 1 และพื้นที่คือ h × width

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

heights = [2, 1, 5, 6, 2, 3]
n = len(heights)

# Find PSE and NSE for each bar
pse = [-1] * n   # index of previous smaller element
nse = [n] * n    # index of next smaller element (default: beyond array)

# PSE
stack = []
for i in range(n):
    while stack and heights[stack[-1]] >= heights[i]:
        stack.pop()
    pse[i] = stack[-1] if stack else -1
    stack.append(i)

# NSE
stack = []
for i in range(n - 1, -1, -1):
    while stack and heights[stack[-1]] >= heights[i]:
        stack.pop()
    nse[i] = stack[-1] if stack else n
    stack.append(i)

max_area = 0
for i in range(n):
    width = nse[i] - pse[i] - 1
    area = heights[i] * width
    print(f'Bar {i} (h={heights[i]}): PSE={pse[i]}, NSE={nse[i]}, width={width}, area={area}')
    max_area = max(max_area, area)
print('Max area:', max_area)

วิธีแก้แบบวนรอบเดียวด้วยสแตกแบบโมโนโทนิก

วิธีแก้แบบสองรอบข้างต้นใช้ได้ แต่สามารถรวมเป็นการวนรอบเดียวได้ ประมวลผลแท่งจากซ้ายไปขวาด้วยสแตกแบบเพิ่มขึ้น เมื่อแท่ง i สั้นกว่าสมาชิกบนสุดของสแตก ให้ pop สมาชิกบนสุดนั้นออก ความสูงของแท่งที่ถูก pop คือความสูงของสี่เหลี่ยมผืนผ้า ขอบเขตขวาคือ i และขอบเขตซ้ายคือสมาชิกบนสุดใหม่ของสแตก + 1

เคล็ดลับมาตรฐานคือ append ค่าเฝ้ายาม 0 ต่อท้าย heights วิธีนี้ทำให้แท่งทั้งหมดถูก pop ออกจากสแตกเมื่อจบ แม้จะไม่มีแท่งที่สั้นกว่าปรากฏขึ้นตามธรรมชาติ หากไม่มีค่าเฝ้ายาม คุณจะต้องมีขั้นตอนทำความสะอาดสมาชิกที่เหลือในสแตกหลังจบลูป

def largest_rectangle(heights):
    stack = []   # monotonic increasing: indices of bars
    max_area = 0
    heights = heights + [0]  # sentinel: forces all bars to be popped

    for i, h in enumerate(heights):
        while stack and heights[stack[-1]] > h:
            height = heights[stack.pop()]       # height of the rectangle
            width = i if not stack else i - stack[-1] - 1  # left boundary
            max_area = max(max_area, height * width)
        stack.append(i)
    return max_area

print(largest_rectangle([2, 1, 5, 6, 2, 3]))  # 10
print(largest_rectangle([2, 4]))               # 4
print(largest_rectangle([1, 1]))               # 2
print(largest_rectangle([0, 9]))               # 9
print(largest_rectangle([6, 7, 5, 2, 4, 5, 9, 3]))  # 16

การติดตามอัลกอริทึมแบบวนรอบเดียว

ให้ติดตาม [2, 1, 5, 6, 2, 3, 0] (มีค่าเฝ้ายาม) ทีละขั้นตอน:

  • i=0, h=2: ใส่ 0 สแตก: [0]
  • i=1, h=1: pop 0 (h=2, width=1, area=2) สแตกว่าง แล้วใส่ 1 สแตก: [1]
  • i=2, h=5: 5>1 ให้ใส่ 2 สแตก: [1,2]
  • i=3, h=6: 6>5 ให้ใส่ 3 สแตก: [1,2,3]
  • i=4, h=2: pop 3 (h=6,width=4-2-1=1,area=6), pop 2 (h=5,width=4-1-1=2,area=10★), 2>1 จึงหยุด ใส่ 4 สแตก: [1,4]
  • i=5, h=3: 3>2 ให้ใส่ 5 สแตก: [1,4,5]
  • i=6, ค่าเฝ้ายาม h=0: pop ทั้งหมดเพื่อคำนวณพื้นที่...
def largest_rectangle_trace(heights):
    stack = []
    max_area = 0
    hs = heights + [0]

    for i, h in enumerate(hs):
        while stack and hs[stack[-1]] > h:
            top = stack.pop()
            w = i if not stack else i - stack[-1] - 1
            area = hs[top] * w
            print(f'  Pop bar {top} (h={hs[top]}): width={w}, area={area}', end='')
            if area > max_area:
                max_area = area
                print(' *** NEW MAX ***', end='')
            print()
        print(f'i={i} h={h}: push {i}, stack={[hs[s] for s in stack + [i]]}')
        stack.append(i)
    print(f'Max area: {max_area}')
    return max_area

largest_rectangle_trace([2, 1, 5, 6, 2, 3])

การคำนวณความกว้าง: เหตุใดจึงเป็น i - stack[-1] - 1

เมื่อเรา pop แท่ง j ออกจากสแตก เราทราบว่า ขอบเขตขวาของสี่เหลี่ยมผืนผ้าของ j คือ i (แท่งแรกทางขวาที่สั้นกว่า j) ขอบเขตซ้ายคือแท่งที่อยู่ถัดลงมาจาก j ในสแตกหลังจาก pop ให้เรียกแท่งนั้นว่า k ดังนั้นความกว้างจึงเป็น i - k - 1 (แท่งตั้งแต่ k+1 ถึง i-1 โดยนับรวมปลายทั้งสองด้าน)

หากสแตกว่างหลังจาก pop สี่เหลี่ยมผืนผ้าของ j จะขยายไปจนถึงขอบซ้ายสุด ความกว้างจะเป็นเพียง i (ดัชนี 0 ถึง i-1 ซึ่งล้วนมีความสูงอย่างน้อยเท่ากับ heights[j]) นี่คือกรณีพิเศษ width = i if not stack else i - stack[-1] - 1

# Illustrating left/right boundary logic
heights = [1, 3, 5, 2]
# After processing with stack:
# When we pop bar 2 (h=5) at i=3 (h=2):
#   stack after pop = [0, 1]   => left boundary = 1+1=2, right=3-1=2 => width=1
# When we pop bar 1 (h=3) at i=3 (h=2):
#   stack after pop = [0]       => left boundary = 0+1=1, right=3-1=2 => width=2
# etc.

def compute_boundaries(heights):
    hs = heights + [0]
    stack = []
    for i, h in enumerate(hs):
        while stack and hs[stack[-1]] > h:
            top = stack.pop()
            if stack:
                left = stack[-1] + 1
                width = i - stack[-1] - 1
            else:
                left = 0
                width = i
            print(f'Bar {top} (h={hs[top]}): extends from {left} to {i-1}, width={width}')
        stack.append(i)

compute_boundaries([2, 1, 5, 6, 2, 3])

สี่เหลี่ยมผืนผ้าที่ใหญ่ที่สุดในเมทริกซ์ไบนารี

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

วิธีนี้ลดปัญหาสองมิติให้เป็นปัญหาฮิสโตแกรมหนึ่งมิติที่ทำซ้ำ n ครั้ง ความซับซ้อนด้านเวลาคือ O(m × n) สำหรับเมทริกซ์ที่มี m แถวและ n คอลัมน์ โดยทำหนึ่งรอบกับฮิสโตแกรมต่อแถว และแต่ละรอบใช้เวลา O(n)

def maximal_rectangle(matrix):
    if not matrix or not matrix[0]:
        return 0
    n = len(matrix[0])
    heights = [0] * n
    max_area = 0

    def hist_max_area(h):
        stack, area = [], 0
        for i, hh in enumerate(h + [0]):
            while stack and h[stack[-1]] > hh:
                top = stack.pop()
                w = i if not stack else i - stack[-1] - 1
                area = max(area, h[top] * w)
            stack.append(i)
        return area

    for row in matrix:
        for j in range(n):
            heights[j] = heights[j] + 1 if row[j] == '1' else 0
        max_area = max(max_area, hist_max_area(heights[:]))
    return max_area

matrix = [['1','0','1','0','0'],
          ['1','0','1','1','1'],
          ['1','1','1','1','1'],
          ['1','0','0','1','0']]
print(maximal_rectangle(matrix))  # 6

กรณีขอบในปัญหาฮิสโตแกรม

กรณีขอบสำคัญที่ต้องจัดการ:

  • ความสูงเท่ากันทั้งหมด: อาร์เรย์ทั้งชุดเป็นสี่เหลี่ยมผืนผ้าเดียว คำตอบ = n × height
  • เพิ่มขึ้นอย่างต่อเนื่อง: จะไม่มีการ pop จนกว่าจะถึงค่าเฝ้ายาม พื้นที่ของแท่งสุดท้ายมีค่ามากที่สุด
  • มีแท่งเดียว: คำตอบ = height[0]
  • แท่งที่มีความสูง 0: แท่งเหล่านี้ทำหน้าที่เป็นค่าเฝ้ายามตามธรรมชาติ และแบ่งฮิสโตแกรมออกเป็นส่วนอิสระจากกัน

ค่าเฝ้ายาม (append 0) ที่ท้ายอาร์เรย์จัดการกรณีที่ความสูงเพิ่มขึ้นอย่างต่อเนื่องด้วยการบังคับให้แท่งที่เหลือทั้งหมดถูก pop เมื่อจบ หากไม่มีค่าเฝ้ายาม คุณจะต้องมีลูปแยกต่างหากเพื่อทำความสะอาดหลังการวนรอบหลัก

def largest_rectangle(heights):
    stack = []
    max_area = 0
    heights = heights + [0]
    for i, h in enumerate(heights):
        while stack and heights[stack[-1]] > h:
            top = stack.pop()
            w = i if not stack else i - stack[-1] - 1
            max_area = max(max_area, heights[top] * w)
        stack.append(i)
    return max_area

# Edge cases
print(largest_rectangle([5, 5, 5, 5]))    # 20 (all same)
print(largest_rectangle([1, 2, 3, 4, 5])) # 9 (increasing: 3*3)
print(largest_rectangle([5, 4, 3, 2, 1])) # 9 (decreasing: 3*3)
print(largest_rectangle([5]))              # 5 (single bar)
print(largest_rectangle([0, 0, 0]))        # 0 (all zero)
print(largest_rectangle([3, 0, 3]))        # 3 (zero splits)

ทางเลือกแบบแบ่งและพิชิต

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

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

def largest_rectangle_dc(heights, lo=0, hi=None):
    if hi is None:
        hi = len(heights) - 1
    if lo > hi:
        return 0
    # Find the index of the minimum height in [lo, hi]
    min_idx = lo
    for i in range(lo, hi + 1):
        if heights[i] < heights[min_idx]:
            min_idx = i
    # Three options:
    # 1. Max rect entirely in left half
    # 2. Max rect entirely in right half
    # 3. Max rect spanning entire [lo, hi] with height = min
    full_width_area = heights[min_idx] * (hi - lo + 1)
    left_area  = largest_rectangle_dc(heights, lo, min_idx - 1)
    right_area = largest_rectangle_dc(heights, min_idx + 1, hi)
    return max(full_width_area, left_area, right_area)

print(largest_rectangle_dc([2, 1, 5, 6, 2, 3]))  # 10

รูปแบบฮิสโตแกรม: จำนวนช่วงย่อย

ปัญหาที่เกี่ยวข้องซึ่งใช้เทคนิคสแตกเดียวกันคือ การนับจำนวนช่วงย่อยในฮิสโตแกรมที่สมาชิกต่ำสุดมีค่าเท่ากับเป้าหมายที่กำหนด คำตอบหาได้จากการคำนวณ PSE และ NSE สำหรับแท่งแต่ละแท่ง แล้วใช้สูตร (i - pse[i]) × (nse[i] - i) ซึ่งนับฮิสโตแกรมย่อยที่แท่ง i เป็นสมาชิกต่ำสุด

เทคนิค 'จำนวนทางซ้าย × จำนวนทางขวา' นี้ปรากฏในปัญหา LeetCode หลายข้อ ได้แก่ ผลรวมของสมาชิกต่ำสุดในช่วงย่อย (907) การนับสตริงย่อยที่มีอักขระไม่ซ้ำกันทั้งหมด และปัญหาที่ใช้เทคนิคการคำนวณส่วนร่วม สแตกแบบโมโนโทนิกคำนวณ PSE และ NSE ได้ในเวลา O(n) ทำให้คำนวณส่วนร่วมของสมาชิกแต่ละตัวได้ในเวลา O(1)

def sum_of_subarray_minimums(arr):
    n = len(arr)
    pse = [-1] * n   # previous strictly smaller element
    nse = [n] * n    # next smaller or equal element

    stack = []
    for i in range(n):
        while stack and arr[stack[-1]] >= arr[i]:
            stack.pop()
        pse[i] = stack[-1] if stack else -1
        stack.append(i)

    stack = []
    for i in range(n - 1, -1, -1):
        while stack and arr[stack[-1]] > arr[i]:
            stack.pop()
        nse[i] = stack[-1] if stack else n
        stack.append(i)

    MOD = 10**9 + 7
    total = 0
    for i in range(n):
        left_count = i - pse[i]          # subarrays where i is leftmost min
        right_count = nse[i] - i        # subarrays where i is the min
        total += arr[i] * left_count * right_count
    return total % MOD

print(sum_of_subarray_minimums([3, 1, 2, 4]))  # 17
print(sum_of_subarray_minimums([11, 81, 94, 43, 3]))  # 444

เคล็ดลับการสัมภาษณ์เชิงปฏิบัติ

เมื่อพบโจทย์ฮิสโตแกรมในการสัมภาษณ์ ให้ทำตามรายการตรวจสอบนี้:

  1. ชี้แจงว่าอนุญาตให้ความสูงเป็น 0 หรือไม่ และผลลัพธ์คือพื้นที่ ดัชนี หรือจำนวน
  2. เริ่มด้วยวิธีลองทุกกรณี และระบุความซับซ้อนเป็น O(n²) หรือ O(n³)
  3. กล่าวถึงการที่ส่วนร่วมของแต่ละแท่งขึ้นอยู่กับระยะขยายไปทางซ้ายและขวาจนถึงแท่งที่สั้นกว่าที่ใกล้ที่สุด
  4. แนะนำ PSE/NSE → สแตกแบบโมโนโทน → วิธีแก้ปัญหา O(n)
  5. จัดการเทคนิคค่าตัวเฝ้ายาม (append 0) เพื่อทำให้โค้ดเรียบง่ายขึ้น
  6. ไล่ดูตัวอย่างขนาดเล็กบนกระดานไวท์บอร์ด

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

# Final clean solution for interview
def largest_rectangle_in_histogram(heights):
    stack = []
    max_area = 0
    for i, h in enumerate(heights + [0]):  # sentinel forces final pops
        while stack and heights[stack[-1]] > h:
            height = heights[stack.pop()]
            width = i if not stack else i - stack[-1] - 1
            max_area = max(max_area, height * width)
        stack.append(i)
    return max_area

# Verify all test cases from earlier
test_cases = [
    ([2, 1, 5, 6, 2, 3], 10),
    ([6, 7, 5, 2, 4, 5, 9, 3], 16),
    ([1], 1),
    ([2, 0, 2], 2),
    ([], 0),
]
for heights, expected in test_cases:
    if not heights:
        result = 0
    else:
        result = largest_rectangle_in_histogram(heights)
    status = 'PASS' if result == expected else 'FAIL'
    print(f'{status}: {heights} => {result} (expected {expected})')

ผลรวมช่วงของอาร์เรย์ย่อยและรูปแบบที่คล้ายกัน

เทคนิค PSE/NSE สามารถนำไปใช้กับโจทย์ LeetCode ได้หลายข้อ ผลรวมช่วงของอาร์เรย์ย่อย (2104) ขอให้หาผลรวมของ (ค่าสูงสุด - ค่าต่ำสุด) ของอาร์เรย์ย่อยทั้งหมด ซึ่งเท่ากับ (ผลรวมของค่าสูงสุดของอาร์เรย์ย่อย) ลบด้วย (ผลรวมของค่าต่ำสุดของอาร์เรย์ย่อย) โดยแต่ละส่วนคำนวณได้ด้วยสแตกแบบโมโนโทนในเวลา O(n) ส่วน จำนวนคนที่มองเห็นได้ในคิว (1944) ใช้สแตกแบบลดลง โดยการ pop แต่ละครั้งนับเป็นคนที่มองเห็นได้หนึ่งคน การจดจำกลุ่มโจทย์นี้ได้เกิดจากการสังเกตวลีว่า “สำหรับแต่ละองค์ประกอบ มันสามารถครอบงำไปได้ไกลเพียงใด” — คำตอบคือ PSE/NSE ด้วยสแตกแบบโมโนโทนเสมอ

def sum_subarray_ranges(nums):
    n = len(nums)
    # Sum of subarray max - sum of subarray min
    def contrib(arr, is_max):
        # Count contribution of each element as max (or min)
        n = len(arr)
        left = [0]*n; right = [0]*n
        stack = []
        for i in range(n):
            while stack and (arr[stack[-1]] < arr[i] if is_max else arr[stack[-1]] > arr[i]):
                stack.pop()
            left[i] = i - (stack[-1] if stack else -1)
            stack.append(i)
        stack = []
        for i in range(n-1, -1, -1):
            while stack and (arr[stack[-1]] <= arr[i] if is_max else arr[stack[-1]] >= arr[i]):
                stack.pop()
            right[i] = (stack[-1] if stack else n) - i
            stack.append(i)
        return sum(arr[i] * left[i] * right[i] for i in range(n))
    return contrib(nums, True) - contrib(nums, False)

print(sum_subarray_ranges([1, 2, 3]))    # 4
print(sum_subarray_ranges([1, 3, 3]))    # 4
print(sum_subarray_ranges([4, -2, -3, 4, 1]))  # 59

ตรวจสอบความเข้าใจ

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

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

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

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

บทเรียน “สี่เหลี่ยมผืนผ้าที่ใหญ่ที่สุดในฮิสโตแกรม” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “สี่เหลี่ยมผืนผ้าที่ใหญ่ที่สุดในฮิสโตแกรม”

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

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

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

บทเรียน “สี่เหลี่ยมผืนผ้าที่ใหญ่ที่สุดในฮิสโตแกรม” ใช้เวลานานแค่ไหน

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

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

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

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

  1. สแตกโมโนโทนิก: เพิ่มขึ้นเทียบกับลดลง
  2. สี่เหลี่ยมผืนผ้าที่ใหญ่ที่สุดในฮิสโตแกรม
  3. ค่าสูงสุดในหน้าต่างเลื่อนด้วยคิวสองทางโมโนโทนิก
  4. กักเก็บน้ำฝน: สแตกและตัวชี้สองตัว
← กลับไปที่ Coding Interview Prep