นับจำนวนคู่กลับลำดับด้วยการเรียงลำดับแบบผสานที่ดัดแปลง
นับจำนวนคู่กลับลำดับในอาร์เรย์ ซึ่งเป็นคู่ที่ a[i] > a[j] และ i < j โดยนับคู่ที่ข้ามส่วนระหว่างขั้นตอนการผสาน
นับจำนวนคู่กลับลำดับด้วยการเรียงลำดับแบบผสานที่ดัดแปลง เป็นบทเรียน Coding Interview Prep ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Coding Interview Prep และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Coding Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน
การผกผันคืออะไร
การผกผันในอาร์เรย์คือคู่ดัชนี (i, j) ที่ i < j แต่ a[i] > a[j] กล่าวคือมีสมาชิกที่ใหญ่กว่าปรากฏก่อนสมาชิกที่เล็กกว่า ตัวอย่างเช่น ใน [3, 1, 2] การผกผันคือ (3,1) และ (3,2) ดังนั้นมีการผกผัน 2 คู่ อาร์เรย์ที่เรียงแล้วมีการผกผัน 0 คู่ อาร์เรย์ที่เรียงย้อนกลับของสมาชิก n ตัวมีการผกผัน n(n-1)/2 คู่ การนับการผกผันใช้วัดว่าอาร์เรย์ห่างจากลำดับที่เรียงแล้วมากเพียงใด
arr = [3, 1, 2]
# Inversions: pairs (i,j) where i<j and arr[i]>arr[j]
inversions = []
for i in range(len(arr)):
for j in range(i+1, len(arr)):
if arr[i] > arr[j]:
inversions.append((arr[i], arr[j]))
print('Inversions in', arr, ':', inversions)
print('Count:', len(inversions)) # 2
# Maximum inversions in n-element array:
import math
n = 5
print(f'Max inversions for n={n}: {n*(n-1)//2}') # 10 for [5,4,3,2,1]วิธีตรงไปตรงมา O(n²)
วิธีตรวจสอบทุกคู่จะตรวจคู่ (i, j) ทั้งหมดที่ i < j และนับคู่ที่ a[i] > a[j] วิธีนี้ใช้เวลา O(n²) และพื้นที่ O(1) เมื่อ n = 10⁵ จะต้องเปรียบเทียบ 5 × 10⁹ ครั้ง ซึ่งช้าเกินไป วิธีแบ่งแยกและพิชิตโดยใช้การเรียงลำดับแบบผสานที่ปรับแก้แล้วแก้ปัญหาได้ในเวลา O(n log n) แนวคิดสำคัญคือ ในระหว่างขั้นตอนการผสานของการเรียงลำดับแบบผสาน เราสามารถนับการผกผันที่ข้ามการแบ่งได้อย่างมีประสิทธิภาพ
def count_inversions_brute(arr):
n = len(arr)
count = 0
for i in range(n):
for j in range(i + 1, n):
if arr[i] > arr[j]:
count += 1
return count
print(count_inversions_brute([3, 1, 2])) # 2
print(count_inversions_brute([5, 4, 3, 2, 1])) # 10
print(count_inversions_brute([1, 2, 3, 4, 5])) # 0
print(count_inversions_brute([2, 4, 1, 3, 5])) # 3แนวคิดสำคัญของการเรียงลำดับแบบผสาน
ระหว่างการผสานครึ่งที่เรียงแล้วสองส่วน L และ R หากเราเลือกสมาชิก R[j] แทน L[i] เพราะ R[j] < L[i] นั่นหมายความว่า สมาชิกที่เหลือทั้งหมด ใน L ตั้งแต่ดัชนี i เป็นต้นไปก็มีค่ามากกว่า R[j] เช่นกัน เนื่องจาก L เรียงลำดับแล้ว ดังนั้นทุกครั้งที่เลือกจากครึ่งขวา เราจะนับการผกผันข้ามครึ่งเป็นจำนวน len(L) - i การนับนี้แทบไม่เพิ่มต้นทุน เพราะเกิดขึ้นระหว่างการผสานตามปกติ
# During merge of [1, 3, 5] and [2, 4, 6]:
# Compare L[0]=1 vs R[0]=2: take L[0]=1, no inversions
# Compare L[1]=3 vs R[0]=2: take R[0]=2, inversions += len(L)-1 = 2 (3>2, 5>2)
# Compare L[1]=3 vs R[1]=4: take L[1]=3, no inversions
# Compare L[2]=5 vs R[1]=4: take R[1]=4, inversions += len(L)-2 = 1 (5>4)
# Compare L[2]=5 vs R[2]=6: take L[2]=5, no inversions
# Take R[2]=6
# Total cross-inversions = 2 + 1 = 3
print('Cross-inversions identified during merge: 3')การนำการเรียงลำดับแบบผสานที่ปรับแก้แล้วไปใช้งาน
ปรับการเรียงลำดับแบบผสานให้คืนค่าทั้ง อาร์เรย์ที่เรียงแล้ว และ จำนวนการผกผัน จำนวนการผกผันทั้งหมด = จำนวนการผกผันในครึ่งซ้าย + จำนวนการผกผันในครึ่งขวา + จำนวนการผกผันข้ามครึ่งที่พบระหว่างการผสาน กรณีฐานคืนค่า (สมาชิกหนึ่งตัว, การผกผัน 0 คู่) ฟังก์ชันผสานจะนับการผกผันขณะผสาน อัลกอริทึมใช้เวลารวม O(n log n)
def count_inversions(arr):
def merge_sort_count(arr):
if len(arr) <= 1:
return arr, 0
mid = len(arr) // 2
left, left_count = merge_sort_count(arr[:mid])
right, right_count = merge_sort_count(arr[mid:])
merged, cross_count = merge_count(left, right)
return merged, left_count + right_count + cross_count
def merge_count(left, right):
result, count = [], 0
i = j = 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i]); i += 1
else:
result.append(right[j]); j += 1
count += len(left) - i # all remaining in left are inversions
result += left[i:] + right[j:]
return result, count
_, total = merge_sort_count(arr)
return total
print(count_inversions([3, 1, 2])) # 2
print(count_inversions([5, 4, 3, 2, 1])) # 10
print(count_inversions([2, 4, 1, 3, 5])) # 3การติดตามการทำงานของอัลกอริทึม
ติดตามการทำงานของ [2, 4, 1, 3]: แบ่งเป็น [2, 4] และ [1, 3] การเรียงย่อยด้านซ้าย: [2, 4] → ได้ [2,4] ที่เรียงแล้ว มีการผกผัน 0 คู่ การเรียงย่อยด้านขวา: [1, 3] → ได้ [1,3] ที่เรียงแล้ว มีการผกผัน 0 คู่ ผสาน [2,4] และ [1,3]: เลือก 1 (เพิ่มจำนวน 2 จาก 2>1 และ 4>1) เลือก 2 (ไม่เพิ่มจำนวน) เลือก 3 (เพิ่มจำนวน 1 จาก 4>3) แล้วเลือก 4 การผกผันข้ามครึ่ง = 3 จำนวนทั้งหมด = 0+0+3 = 3 ตรวจสอบได้ว่า คู่ (2,1), (4,1), (4,3) = การผกผัน 3 คู่ ✓
def count_with_trace(arr):
def ms(arr, depth=0):
indent = ' ' * depth
if len(arr) <= 1: return arr, 0
mid = len(arr) // 2
L, lc = ms(arr[:mid], depth+1)
R, rc = ms(arr[mid:], depth+1)
merged, cc = merge_c(L, R)
print(f'{indent}merge({L},{R}) → cross={cc}')
return merged, lc + rc + cc
def merge_c(L, R):
res, c, i, j = [], 0, 0, 0
while i < len(L) and j < len(R):
if L[i] <= R[j]: res.append(L[i]); i += 1
else: res.append(R[j]); j += 1; c += len(L) - i
return res + L[i:] + R[j:], c
_, total = ms(arr)
return total
print('Total inversions:', count_with_trace([2, 4, 1, 3]))เหตุใดจึงนับการผกผันข้ามครึ่งได้ถูกต้อง
ความถูกต้อง: คู่การผกผันใด ๆ (a[i], a[j]) ที่ i < j จะอยู่ในหนึ่งในสามประเภทต่อไปนี้อย่างแน่นอน: (1) อยู่ในครึ่งซ้ายทั้งคู่ — นับโดยการเรียกซ้ำทางซ้าย (2) อยู่ในครึ่งขวาทั้งคู่ — นับโดยการเรียกซ้ำทางขวา (3) สมาชิกในครึ่งซ้ายมีค่ามากกว่าสมาชิกในครึ่งขวา — นับระหว่างการผสานเป็นการผกผันข้ามครึ่ง ทั้งสามประเภทไม่ทับซ้อนกันและครอบคลุมทุกกรณี ดังนั้นจึงไม่มีการนับการผกผันซ้ำหรือตกหล่น อาร์กิวเมนต์การแบ่งประเภทนี้คือการพิสูจน์ความถูกต้องมาตรฐานของการแบ่งแยกและพิชิต
# Verification: compare with brute force on random arrays
import random
def count_brute(arr):
n = len(arr)
return sum(1 for i in range(n) for j in range(i+1,n) if arr[i]>arr[j])
def count_dc(arr):
def ms(a):
if len(a)<=1: return a, 0
m=len(a)//2
L,lc=ms(a[:m]); R,rc=ms(a[m:])
res,c,i,j=[],0,0,0
while i<len(L) and j<len(R):
if L[i]<=R[j]: res.append(L[i]);i+=1
else: res.append(R[j]);j+=1;c+=len(L)-i
return res+L[i:]+R[j:],(lc+rc+c)
return ms(arr)[1]
for _ in range(100):
arr = random.choices(range(20), k=random.randint(1,10))
assert count_dc(arr[:]) == count_brute(arr), 'MISMATCH!'
print('All 100 random tests passed!')การประยุกต์ใช้จำนวนการผกผัน
การผกผันใช้วัด ความเป็นระเบียบของการเรียงลำดับ การประยุกต์ใช้ ได้แก่ (1) ความสัมพันธ์ของการจัดอันดับ: ระยะห่างเคนดัลล์เทาระหว่างรายการที่จัดอันดับสองรายการคือจำนวนการผกผัน (2) ประสิทธิภาพของการเรียงลำดับแบบแทรก: การเรียงลำดับแบบแทรกทำการสลับจำนวนครั้งเท่ากับจำนวนการผกผันพอดี (3) การวิเคราะห์การเรียงลำดับแบบฟอง: การวนรอบแต่ละครั้งของการเรียงลำดับแบบฟองลดจำนวนการผกผันลง และจำนวนรอบที่ต้องใช้เท่ากับจำนวนการผกผัน (4) ความสามารถในการแก้ปริศนา: ปริศนา 8 ช่องหรือ 15 ช่องจะแก้ได้ก็ต่อเมื่อจำนวนการผกผันมีความเป็นคู่คี่ตามที่กำหนด
# Kendall tau: number of inversions between two rankings
# Useful for comparing search result rankings or recommendation systems
def kendall_tau(rank1, rank2):
'''Count inversions where rank1 and rank2 disagree on relative order.'''
# Map rank2 positions to create a comparison sequence
pos = {v: i for i, v in enumerate(rank2)}
# Convert rank1 to position-in-rank2 ordering
arr = [pos[v] for v in rank1]
return count_inversions(arr)
def count_inversions(arr):
def ms(a):
if len(a)<=1: return a,0
m=len(a)//2; L,lc=ms(a[:m]); R,rc=ms(a[m:])
res,c,i,j=[],0,0,0
while i<len(L) and j<len(R):
if L[i]<=R[j]: res.append(L[i]);i+=1
else: res.append(R[j]);j+=1;c+=len(L)-i
return res+L[i:]+R[j:],(lc+rc+c)
return ms(arr[:])[1]
print(kendall_tau([1,2,3],[3,1,2])) # measures disagreementที่เกี่ยวข้อง: นับจำนวนที่น้อยกว่าหลังสมาชิกปัจจุบัน
นับจำนวนที่น้อยกว่าหลังสมาชิกปัจจุบัน (LeetCode 315) ถามสำหรับสมาชิกแต่ละตัวว่า มีสมาชิกทางขวากี่ตัวที่มีค่าน้อยกว่า นี่คือการนับการผกผันแยกตามสมาชิก สามารถแก้ได้ด้วยการเรียงลำดับแบบผสานที่ปรับแก้แล้วแบบเดียวกัน โดยติดตามว่าดัชนีเดิมใดถูกนับ หรือใช้ต้นไม้ดัชนีทวิภาค (ต้นไม้เฟนวิก) หรือการเรียงลำดับแบบผสานที่ติดตามดัชนี วิธีแบ่งแยกและพิชิตใช้เวลา O(n log n)
def count_smaller(nums):
n = len(nums)
result = [0] * n
indexed = list(enumerate(nums))
def merge_sort(arr):
if len(arr) <= 1: return arr
mid = len(arr) // 2
left = merge_sort(arr[:mid])
right = merge_sort(arr[mid:])
return merge(left, right)
def merge(left, right):
merged = []
i = j = 0
while i < len(left) and j < len(right):
if left[i][1] <= right[j][1]:
# left[i] is placed; j elements from right are smaller and to the right
result[left[i][0]] += j
merged.append(left[i]); i += 1
else:
merged.append(right[j]); j += 1
while i < len(left):
result[left[i][0]] += j # all of right is smaller
merged.append(left[i]); i += 1
return merged + right[j:]
merge_sort(indexed)
return result
print(count_smaller([5, 2, 6, 1])) # [2, 1, 1, 0]คู่ย้อนกลับ
คู่ย้อนกลับ (LeetCode 493) นับคู่ (i, j) ที่ i < j และ nums[i] > 2 × nums[j] การนับการผกผันมาตรฐานใช้เงื่อนไข nums[i] > nums[j] แต่ในกรณีนี้เกณฑ์เปลี่ยนเป็น 2 × nums[j] ให้ปรับการเรียงลำดับแบบผสานโดยนับคู่ข้ามการแบ่งก่อนการผสาน ใช้ตัวชี้สองตัวเพื่อนับขณะที่ครึ่งซ้ายยังมีสมาชิกที่เข้าเงื่อนไข จากนั้นจึงผสานตามปกติ ใช้เวลารวม O(n log n)
def reverse_pairs(nums):
def merge_sort_count(arr):
if len(arr) <= 1: return arr, 0
mid = len(arr) // 2
L, lc = merge_sort_count(arr[:mid])
R, rc = merge_sort_count(arr[mid:])
# Count cross pairs: L[i] > 2*R[j]
j = 0
cross = 0
for l_val in L:
while j < len(R) and l_val > 2 * R[j]:
j += 1
cross += j
# Normal merge (separate from count)
merged = []
i = jj = 0
while i < len(L) and jj < len(R):
if L[i] <= R[jj]: merged.append(L[i]); i += 1
else: merged.append(R[jj]); jj += 1
merged += L[i:] + R[jj:]
return merged, lc + rc + cross
return merge_sort_count(nums)[1]
print(reverse_pairs([1, 3, 2, 3, 1])) # 2
print(reverse_pairs([2, 4, 3, 5, 1])) # 3เปรียบเทียบจำนวนอินเวอร์ชันแบบสากลกับแบบเฉพาะที่
อินเวอร์ชันแบบสากลและแบบเฉพาะที่ (LeetCode 775): กำหนดการเรียงสับเปลี่ยนของ 0..n-1 ให้ตรวจสอบว่าจำนวนอินเวอร์ชันแบบสากล (คู่ทั้งหมด i<j ที่ a[i]>a[j]) เท่ากับจำนวนอินเวอร์ชันแบบเฉพาะที่ (คู่สมาชิกที่อยู่ติดกัน) หรือไม่ ข้อสังเกตสำคัญคือ อินเวอร์ชันแบบเฉพาะที่ทุกคู่เป็นอินเวอร์ชันแบบสากลด้วย ดังนั้นจำนวนอินเวอร์ชันแบบสากลจึงมากกว่าหรือเท่ากับจำนวนแบบเฉพาะที่ ทั้งสองจำนวนจะเท่ากันก็ต่อเมื่อไม่มีอินเวอร์ชันระหว่างสมาชิกที่ไม่ได้อยู่ติดกัน ซึ่งหมายความว่าไม่มีสมาชิกใดอยู่ห่างจากดัชนีเมื่อเรียงลำดับแล้วเกิน 1 ตำแหน่ง จึงลดรูปเป็นการตรวจสอบว่า abs(a[i] - i) ≤ 1 สำหรับ i ทุกตัว
def is_ideal_permutation(A):
'''Global inversions == local inversions
iff no element is more than 1 position from its sorted index.'''
return all(abs(a - i) <= 1 for i, a in enumerate(A))
print(is_ideal_permutation([1, 0, 2])) # True
print(is_ideal_permutation([1, 2, 0])) # False (A[0]=1 is far from 2, A[2]=0 is far)
# Verification with inversion counts
print(count_inversions([1, 0, 2])) # 1 (global)
local1 = sum(1 for i in range(len([1,0,2])-1) if [1,0,2][i]>[1,0,2][i+1])
print('local:', local1) # 1 (equal)
def count_inversions(arr):
def ms(a):
if len(a)<=1: return a,0
m=len(a)//2; L,lc=ms(a[:m]); R,rc=ms(a[m:])
res,c,i,j=[],0,0,0
while i<len(L) and j<len(R):
if L[i]<=R[j]: res.append(L[i]);i+=1
else: res.append(R[j]);j+=1;c+=len(L)-i
return res+L[i:]+R[j:],(lc+rc+c)
return ms(arr[:])[1]สรุปความซับซ้อนของจำนวนอินเวอร์ชัน
สรุป: การนับอินเวอร์ชันด้วยวิธีตรวจสอบทุกคู่มีความซับซ้อน O(n²) ส่วนการเรียงลำดับแบบผสานที่ปรับปรุงแล้วทำได้ O(n log n) โดยนับอินเวอร์ชันข้ามส่วนแบ่งระหว่างขั้นตอนการผสาน ค่าใช้จ่ายเพิ่มเติมคือ O(1) ต่อการเปรียบเทียบ (บวก len(left) - i) ดังนั้นค่าใช้จ่ายโดยรวมจึงเป็น O(n) ต่อระดับการผสาน ซึ่งเท่ากับการเรียงลำดับแบบผสานมาตรฐาน การใช้พื้นที่เป็น O(n) สำหรับอาร์เรย์ช่วย นี่คือตัวอย่างมาตรฐานของการใช้การแบ่งแยกและพิชิต (D&C) เพื่อนับสถิติลำดับในเวลาเชิงเส้นลอการิทึม
import time, random
def time_method(func, arr):
start = time.time()
result = func(arr[:])
return result, time.time() - start
def count_brute(arr):
return sum(1 for i in range(len(arr)) for j in range(i+1,len(arr)) if arr[i]>arr[j])
def count_dc(arr):
def ms(a):
if len(a)<=1: return a,0
m=len(a)//2;L,lc=ms(a[:m]);R,rc=ms(a[m:])
res,c,i,j=[],0,0,0
while i<len(L) and j<len(R):
if L[i]<=R[j]: res.append(L[i]);i+=1
else: res.append(R[j]);j+=1;c+=len(L)-i
return res+L[i:]+R[j:],(lc+rc+c)
return ms(arr[:])[1]
arr = random.sample(range(1000), 1000)
r1, t1 = time_method(count_brute, arr)
r2, t2 = time_method(count_dc, arr)
print(f'Brute: {r1} in {t1:.4f}s')
print(f'D&C: {r2} in {t2:.4f}s')
print(f'Speedup: {t1/t2:.1f}x')ตรวจสอบความเข้าใจอย่างรวดเร็ว
ทดสอบความเข้าใจแนวคิดด้านโครงสร้างข้อมูลและอัลกอริทึม — การเตรียมตัวสัมภาษณ์เขียนโค้ดจากบทเรียนนี้
ทบทวนบทเรียน
ในบทเรียนนี้คุณได้เรียนรู้ว่า อินเวอร์ชันใช้วัดว่าอาร์เรย์ไม่เป็นระเบียบเพียงใด โดยมีความซับซ้อน O(n²) สำหรับวิธีตรวจสอบทุกคู่ และ O(n log n) สำหรับการแบ่งแยกและพิชิต การเรียงลำดับแบบผสานที่ปรับปรุงแล้วจะนับอินเวอร์ชันข้ามครึ่งด้วยการบวก len(left)-i ทุกครั้งที่เลือกสมาชิกจากฝั่งขวามาก่อนสมาชิกจากฝั่งซ้าย และ ความถูกต้องอาศัยการแบ่งกรณีเป็นอินเวอร์ชันภายในฝั่งซ้าย อินเวอร์ชันภายในฝั่งขวา และอินเวอร์ชันข้ามฝั่ง ซึ่งไม่ทับซ้อนกันและรวมกันครอบคลุมอินเวอร์ชันทั้งหมด ต่อไปเราจะศึกษาอัลกอริทึมการลงคะแนนแบบ Boyer-Moore เพื่อค้นหาสมาชิกเสียงข้างมาก
คำถามที่พบบ่อย
บทเรียน “นับจำนวนคู่กลับลำดับด้วยการเรียงลำดับแบบผสานที่ดัดแปลง” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “นับจำนวนคู่กลับลำดับด้วยการเรียงลำดับแบบผสานที่ดัดแปลง” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Coding Interview Prep ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Coding Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “นับจำนวนคู่กลับลำดับด้วยการเรียงลำดับแบบผสานที่ดัดแปลง”
นับจำนวนคู่กลับลำดับในอาร์เรย์ ซึ่งเป็นคู่ที่ a[i] > a[j] และ i < j โดยนับคู่ที่ข้ามส่วนระหว่างขั้นตอนการผสาน คุณปฏิบัติ 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- แม่แบบการแบ่งและพิชิต
- นับจำนวนคู่กลับลำดับด้วยการเรียงลำดับแบบผสานที่ดัดแปลง
- สมาชิกเสียงข้างมาก: การลงคะแนนแบบ Boyer-Moore
- มัธยฐานของอาร์เรย์เรียงลำดับสองชุด