กำหนดสตริง ต้องการหา จำนวนครั้งน้อยที่สุด (Minimum Cuts) ในการตัดสตริง ทำให้ทุกชิ้นเป็นพาลินโดรม
ตัวอย่าง Input และ Output
Input: "ababbbabbababa" Output: Min cuts for Palindrome Partitioning is: 3 Palindromes: a | babbbab | b | ababa
อัลกอริทึม Dynamic Programming
ฟังก์ชัน minPalPart(str)
ใช้ 2 ตาราง:
pal[i][j]: true ถ้า str[i..j] เป็นพาลินโดรมcut[i][j]: minimum cuts สำหรับ str[i..j]
ขั้นตอน:
- Base case:
pal[i][i] = true, cut[i][i] = 0(ตัวเดียว) - for len = 2 ถึง n:
- for i = 0 ถึง n-len:
- j = i + len - 1
- เช็คพาลินโดรม:
- len=2:
pal[i][j] = (str[i] == str[j]) - len>2:
pal[i][j] = (str[i]==str[j]) && pal[i+1][j-1]
- len=2:
- คำนวณ cut:
- ถ้า
pal[i][j]→cut[i][j] = 0 - มิฉะนั้น:
cut[i][j] = min over k (cut[i][k] + cut[k+1][j] + 1)สำหรับ k = i ถึง j-1
- ถ้า
- for i = 0 ถึง n-len:
- คืน
cut[0][n-1]
ตัวอย่างโค้ด C++
#include <iostream>
#include <string>
#include <climits>
#include <algorithm>
using namespace std;
int minPalPartion(string str) {
int n = str.size();
int cut[n][n];
bool pal[n][n];
for (int i = 0; i < n; i++) {
pal[i][i] = true;
cut[i][i] = 0;
}
for (int len = 2; len <= n; len++) {
for (int i = 0; i < n-len+1; i++) {
int j = i + len - 1;
if (len == 2)
pal[i][j] = (str[i] == str[j]);
else
pal[i][j] = (str[i] == str[j]) && pal[i+1][j-1];
if (pal[i][j])
cut[i][j] = 0;
else {
cut[i][j] = INT_MAX;
for (int k = i; k <= j-1; k++)
cut[i][j] = min(cut[i][j], cut[i][k] + cut[k+1][j] + 1);
}
}
}
return cut[0][n-1];
}
int main() {
string str = "ababbbabbababa";
cout << "Min cuts for Palindrome Partitioning is: " << minPalPartion(str);
return 0;
}
Output
Min cuts for Palindrome Partitioning is: 3
ความซับซ้อน
- Time: O(n³) - len, i, k ทั้งสามลูป
- Space: O(n²)
การเพิ่มประสิทธิภาพเป็น O(n²)
คำนวณ cut[i] = min cuts สำหรับ prefix str[0..i] แทน:
cut[i] = min(cut[j-1] + 1) สำหรับ j ที่ str[j..i] เป็นพาลินโดรม (ใช้ pal table เช็ค O(1))