A string prefix search problem.
Given a list of strings, determine whether any of them is a prefix of another. A brute-force O(n2)
solution will get time limit exceeded.
If we sort the strings lexicographically, the problem gets easier. In the sorted string list s
, if any string s[i]
is a prefix of s[i+k]
, then s[i]
is a prefix of all strings from s[i+1]
to s[i+k]
. So, we only need to compare each consecutive strings. Now, our algorithm has complexity O(n)
.
Java implementation with rank 752:
import java.util.*; public class Main { public static void main(String[] args) { ArrayList<String> lst = new ArrayList<String>(); int t, n, i; Scanner s = new Scanner(System.in); t = s.nextInt(); while (t-- > 0) { // input lst.clear(); n = s.nextInt(); s.nextLine(); for (i = 0; i < n; i++) lst.add(s.nextLine().trim()); // solve Collections.sort(lst); for (i = 1; i < n; i++) if (lst.get(i).indexOf(lst.get(i - 1)) == 0) break; if (i == n) System.out.println("YES"); else System.out.println("NO"); } } }
Another variant of the solution (same algorithm though) is to handle the phones as pairs of integers (the first is the phone number itself and the second is a mask that tells which digits of it are actually set). For prefix check, I utilized bit-wise operations. C++ implementation with rank 13:
#include <cstdio> #include <algorithm> using namespace std; bool cmp(pair<long long, long long> i, pair<long long, long long> j) { return (i.first < j.first); } char ans[2][8] = { "NO", "YES" }; int nCase, nPhones; pair<long long, long long> phones[10002]; char line[11]; int main() { int i, j; scanf("%d", &nCase); while (nCase--) { // input scanf("%d", &nPhones); for (i = 0; i < nPhones; ++i) { scanf("%s", line); phones[i].first = 0; phones[i].second = 0; for (j = 0; line[j]; ++j) { phones[i].first = (phones[i].first << 4) | (line[j] - '0' + 1); phones[i].second = (phones[i].second << 4) | (0xF); } while (!(phones[i].first & 0xF000000000)) { phones[i].first <<= 4; phones[i].second <<= 4; } } // solve sort(phones, phones + nPhones, cmp); for (i = 1; i < nPhones; ++i) if ((phones[i].first & phones[i - 1].second) == phones[i - 1].first) break; printf("%s\n", ans[i == nPhones]); } return 0; }