โจทย์
กำหนด string s และ queries หลายๆ query แต่ละ query = [left, right, k] หมายถึง substring s[left:right+1] เราสามารถ:
- เรียงลำดับตัวอักษรใน substring ได้อย่างอิสระ
- เปลี่ยนตัวอักษรได้สูงสุด
kตัว (เปลี่ยนเป็นตัวอักษร lowercase ใดๆ)
ถ้าสามารถทำให้เป็น palindrome ได้ → คืน true, มิฉะนั้น false
ตัวอย่าง: s = "abcda", queries = [[3,3,0],[1,2,0],[0,3,1],[0,3,2],[0,4,1]] → Output: [true, false, false, true, true]
ข้อสังเกตสำคัญ
Palindrome ต้องมีตัวอักษรที่มีความถี่คี่ (odd frequency) ไม่เกิน 1 ตัว (ตัวกลาง) ดังนั้น:
- นับความถี่ตัวอักษรใน substring
- นับจำนวนตัวอักษรที่มีความถี่คี่ =
odd_count - ต้องเปลี่ยนตัวอักษรอย่างน้อย
odd_count // 2ครั้ง เพื่อทำให้คี่เหลือ ≤ 1 - เงื่อนไข:
odd_count // 2 <= k
การเพิ่มประสิทธิภาพ: Prefix Sum (DP)
สร้าง Prefix Frequency Array dp[i][c] = จำนวนตัวอักษร c ใน s[0:i] (1-indexed) เพื่อ query ความถี่ในช่วง O(1)
การติดตั้ง (Python Implementation)
class Solution:
def canMakePaliQueries(self, s: str, queries: list[list[int]]) -> list[bool]:
n = len(s)
# dp[i][j] = count of char j in s[0:i] (1-indexed, dp[0] = all zeros)
dp = [[0] * 26 for _ in range(n + 1)]
# Build prefix sums
for i in range(1, n + 1):
for j in range(26):
dp[i][j] = dp[i-1][j]
dp[i][ord(s[i-1]) - ord('a')] += 1
def solve(l: int, r: int, k: int) -> bool:
# l, r เป็น 0-indexed, แปลงเป็น 1-indexed สำหรับ dp
l += 1
r += 1
odd_count = 0
for j in range(26):
freq = dp[r][j] - dp[l-1][j]
odd_count += freq % 2
return (odd_count // 2) <= k
return [solve(l, r, k) for l, r, k in queries]
# ทดสอบ
ob = Solution()
s = "abcda"
queries = [[3,3,0],[1,2,0],[0,3,1],[0,3,2],[0,4,1]]
print(ob.canMakePaliQueries(s, queries))
# [True, False, False, True, True]
Output
[True, False, False, True, True]
การวิเคราะห์ตัวอย่าง
| Query | Substring | Freq | Odd Count | Need Changes | k | Result |
|---|---|---|---|---|---|---|
| [3,3,0] | "d" | d:1 | 1 | 0 | 0 | True |
| [1,2,0] | "bc" | b:1, c:1 | 2 | 1 | 0 | False |
| [0,3,1] | "abcd" | a:1,b:1,c:1,d:1 | 4 | 2 | 1 | False |
| [0,3,2] | "abcd" | a:1,b:1,c:1,d:1 | 4 | 2 | 2 | True |
| [0,4,1] | "abcda" | a:2,b:1,c:1,d:1 | 3 | 1 | 1 | True |
Complexity
- Preprocessing: O(n × 26) = O(n)
- Per Query: O(26) = O(1)
- Total: O(n + q) - เหมาะสำหรับ queries จำนวนมาก
สรุป
ใช้ Prefix Sum (DP) เก็บความถี่สะสม ทำให้ query แต่ละอันทำได้ O(26) = O(1) เทคนิคนี้ใช้ได้กับโจทย์หลายรูปแบบที่ต้อง query ความถี่ในช่วงบ่อยๆ
หากมีข้อสงสัย สามารถถามได้ในส่วนความคิดเห็นครับ