On this page
ข้อ 51 · LC2542 Maximum Subsequence Score (คะแนน subsequence มากสุด) 🟡
score (คะแนน) = sum (ผลรวม) nums1 คูณ min ของ nums2 ตรึง min ไว้ด้วยการ sort แล้วใช้ min-heap maintain sum nums1 ให้มากสุด
โจทย์ (LC2542): กำหนด array จำนวนเต็ม nums1 และ nums2 ที่ยาวเท่ากัน n ตัว พร้อมจำนวนเต็มบวก k ให้เลือก index มา k ตำแหน่งจาก nums1 (แบบ subsequence) โดยนิยาม score (คะแนน) ของชุดที่เลือกคือ ผลรวมของค่า nums1 ที่ตำแหน่งที่เลือก คูณด้วยค่า minimum ของ nums2 ที่ตำแหน่งเดียวกันที่เลือก ให้ return score ที่มากที่สุดที่เป็นไปได้
- Input:
- nums1 = [1, 3, 3, 2], nums2 = [2, 1, 3, 4], k = 3
- Output:
- 12
- Explanation:
- เลือก index 0, 2, 3: ผลรวม nums1 = 1+3+2 = 6, min ของ nums2 ที่เลือก = min(2,3,4) = 2, คะแนน = 6*2 = 12 (ถ้าเลือก index 0,1,2 แทนจะได้แค่ (1+3+3)*min(2,1,3) = 7 ซึ่งน้อยกว่า)
- Input:
- nums1 = [4, 2, 3, 1, 1], nums2 = [7, 5, 10, 9, 6], k = 1
- Output:
- 30
- Explanation:
- k = 1 เลือกได้ตัวเดียว การเลือก index 2 ให้คะแนนดีที่สุด: nums1[2] * nums2[2] = 3 * 10 = 30
- n == nums1.length == nums2.length
- 1 <= n <= 10^5
- 0 <= nums1[i], nums2[j] <= 10^5
- 1 <= k <= n
แนวทาง — ต้องใช้อะไร & คิดยังไง
โครงสร้างที่ใช้: sort (เรียง) + min-heap ความยากของโจทย์คือ score ขึ้นกับสองอย่างพร้อมกัน: sum nums1 (ยิ่งมากยิ่งดี) กับ min ของ nums2 (ยิ่งมากยิ่งดี) การ handle สองตัวแปรพร้อมกันยาก เทคนิคคือ ตรึง (fix) ตัวหนึ่งไว้ก่อน
คิดแบบง่าย/ช้าก่อน: ลองทุก subset (สับเซ็ต) ขนาด k แล้วคิด score เป็น O(C(n,k)) ซึ่งระเบิดทันที เราจึง sort คู่ (nums1, nums2) ตาม nums2 จากมากไปน้อย แล้ว iterate ไปทีละตัว เมื่อถึงคู่ที่ nums2 = b เราตั้งให้ b เป็นตัว minimum ของกลุ่ม แปลว่าเลือกได้เฉพาะตัวที่มาก่อนหน้า (nums2 ใหญ่กว่าหรือเท่ากับ b) เท่านั้น
- จับคู่ zip(nums1, nums2) แล้ว sort ตาม nums2 จากมากไปน้อย
- iterate ทีละคู่ (a, b): push a เข้า min-heap และบวก a เข้าตัวแปร total
- ถ้า heap เกิน k ตัว ให้ pop ตัว nums1 ที่ minimum ออก พร้อมลบมันออกจาก total
- เมื่อ heap ครบ k ตัวพอดี b ตัวปัจจุบันคือ min ของ nums2 ในกลุ่ม compute total * b แล้ว track ค่ามากสุดไว้ใน best
ลืม update total ตอน pop (ต้องลบค่าที่ pop ออกด้วย) หรือ compute score ตอนที่ heap ยังไม่ครบ k ตัว ต้องเช็ค len(heap) == k ก่อนคิด score เสมอ
ไล่ทีละสเต็ป
จำลอง nums1 = [1,3,3,2], nums2 = [2,1,3,4], k = 3 หลัง sort ตาม nums2 มากไปน้อยได้ pairs = [(2,4),(3,3),(1,2),(3,1)]:
| คู่ (a,b) | heap หลัง push | total | เกิน k? (pop) | คิด total*b เมื่อครบ k |
|---|---|---|---|---|
| (2,4) | [2] | 2 | ไม่ | - |
| (3,3) | [2,3] | 5 | ไม่ | - |
| (1,2) | [1,3,2] | 6 | ไม่ | 6*2 = 12 |
| (3,1) | [3,3,3] | 9→8 | ใช่ pop 1 | 8*1 = 8 |
best = max(12, 8) = 12
▶ เฉลยละเอียด (ลองเองก่อนนะ)
import heapq
def max_score(nums1, nums2, k):
# จับคู่แล้วเรียงตาม nums2 จากมากไปน้อย
pairs = sorted(zip(nums1, nums2), key=lambda p: -p[1])
heap = [] # min-heap เก็บค่า nums1 ของตัวที่เลือกไว้
total = 0 # ผลรวม nums1 ในกลุ่มที่เลือก
best = 0
for a, b in pairs:
heapq.heappush(heap, a)
total += a
# ถ้าเลือกเกิน k ตัว ทิ้ง nums1 ที่น้อยสุดออก
if len(heap) > k:
total -= heapq.heappop(heap)
# เมื่อครบ k ตัว: b ตัวปัจจุบันคือ min ของ nums2 ในกลุ่ม (เพราะเรียงลดหลั่น)
if len(heap) == k:
best = max(best, total * b)
return best
print(max_score([1, 3, 3, 2], [2, 1, 3, 4], 3)) # 12
print(max_score([4, 2, 3, 1, 1], [7, 5, 10, 9, 6], 1)) # 3012
30เมื่อเรา sort ตาม nums2 จากมากไปน้อย แล้ว iterate ไปทีละตัว ณ คู่ปัจจุบัน b คือ nums2 ที่เล็กที่สุดในบรรดาคู่ที่เห็นมาแล้ว (เพราะที่มาก่อนหน้าล้วนมี nums2 มากกว่าหรือเท่ากับ b) ดังนั้นถ้าเราเลือก k ตัวจากกลุ่มที่เห็นมาแล้วโดยรวม b ด้วย min ของ nums2 ในกลุ่มจะเป็น b พอดี
เมื่อ b ถูก fix เป็น min แล้ว เราแค่อยากให้ sum nums1 ของ k ตัวมากที่สุด จึงใช้ min-heap ขนาด k เก็บค่า nums1 พร้อมตัวแปร total ตาม sum ไว้ เมื่อ heap เกิน k ก็ evict nums1 ตัวเล็กสุดออก (พร้อมลบออกจาก total) ถ้าไม่ลบออกจาก total score จะเพี้ยนสูงเกินจริงทันที
Time O(n log n) จากการ sort บวกการ iterate push/pop heap อีก O(n log k) · Space O(n) สำหรับ array คู่ที่ sort แล้ว และ heap ขนาด k
โจทย์ที่ score ขึ้นกับสอง factor (ปัจจัย) พร้อมกัน ให้ fix ปัจจัยหนึ่งด้วยการ sort (ตัวคูณ min/max) แล้วปล่อยให้ heap จัดการอีก factor (sum top-k) เป็น pattern ที่เจอบ่อยในโจทย์ optimize สองมิติ