โจทย์: หา Longest Common Prefix (LCP) ของชุดสตริงหลายตัว คือ Prefix ที่ยาวที่สุดที่ทุกสตริงมีร่วมกัน
Algorithm: Horizontal Scanning
- ตั้ง Prefix เริ่มต้น = String ตัวแรก
- Iterate String ตัวถัดไป: หา Common Prefix ระหว่าง Prefix ปัจจุบัน กับ String นี้
- อัปเดต Prefix ให้สั้นลงตามที่ Match
- ถ้า Prefix ว่าง → หยุดทันที (ไม่มี Common Prefix)
Complexity
- Time: O(S) โดย S = Sum of all characters ใน Strings ทั้งหมด
- Space: O(1) Extra Space
โค้ด C++
#include <bits/stdc++.h>
using namespace std;
// หา Common Prefix ระหว่าง 2 Strings
string commonPrefix(const string& s1, const string& s2) {
int n = min(s1.length(), s2.length());
int i = 0;
while (i < n && s1[i] == s2[i]) i++;
return s1.substr(0, i);
}
// หา LCP ของ Array
string longestCommonPrefix(vector& strs) {
if (strs.empty()) return "";
string prefix = strs[0];
for (size_t i = 1; i < strs.size(); i++) {
prefix = commonPrefix(prefix, strs[i]);
if (prefix.empty()) break; // Early exit
}
return prefix;
}
// Overload สำหรับ Array แบบเดิม
string longestCommonPrefix(string a[], int n) {
if (n == 0) return "";
string pre = a[0];
for (int i = 1; i < n; i++)
pre = commonPrefix(pre, a[i]);
return pre;
}
int main() {
string arr[] = {"Tutorialspoint", "Tutor", "Tutorials"};
int n = sizeof(arr) / sizeof(arr[0]);
string result = longestCommonPrefix(arr, n);
if (!result.empty())
cout << "Longest Common Prefix: " << result << '\n';
else
cout << "No common prefix\n";
return 0;
}
ผลลัพธ์
Longest Common Prefix: Tutor
Alternative Algorithms
1. Vertical Scanning (Column by Column)
string lcpVertical(vector& strs) { if (strs.empty()) return ""; for (int col = 0; col < strs[0].size(); col++) { char c = strs[0][col]; for (int row = 1; row < strs.size(); row++) { if (col == strs[row].size() || strs[row][col] != c) return strs[0].substr(0, col); } } return strs[0]; }
2. Divide & Conquer
string lcpDC(vector& strs, int l, int r) { if (l == r) return strs[l]; int mid = (l + r) / 2; string left = lcpDC(strs, l, mid); string right = lcpDC(strs, mid+1, r); return commonPrefix(left, right); }
3. Binary Search on Length
bool isCommonPrefix(vector& strs, int len) { string prefix = strs[0].substr(0, len); for (int i = 1; i < strs.size(); i++) if (strs[i].compare(0, len, prefix) != 0) return false; return true; } string lcpBinary(vector & strs) { if (strs.empty()) return ""; int minLen = INT_MAX; for (auto& s : strs) minLen = min(minLen, (int)s.length()); int low = 0, high = minLen; while (low <= high) { int mid = (low + high) / 2; if (isCommonPrefix(strs, mid)) low = mid + 1; else high = mid - 1; } return strs[0].substr(0, (low + high) / 2); }
Trie-based Approach (สำหรับ Query หลายครั้ง)
สร้าง Trie จาก Strings ทั้งหมด LCP = Path จาก Root จนกว่าจะมี Branch > 1 หรือจบคำ
การประยุกต์ใช้
- Autocomplete / Search Suggestions
- File Path Common Directory
- DNA Sequence Analysis
- URL Routing Prefix Matching