兩道經典字串處理面試題:去重 保留首次出現順序,壓縮 連續重複字元編碼為「次數+字元」。限定輸入為小寫字母 a-z,需實作 C 風格函式簽名,對應 Java 陣列操作。
規則:出現重複字元,僅保留第一次出現,其餘濾除。
範例:"abacacde" → "abcde"、"deefd" → "def"、"afafafaf" → "af"
/**
* 字串去重:保留首次出現順序
* @param input 輸入字元陣列
* @param len 有效長度
* @param output 輸出緩衝區(呼叫端預分配,長度 >= len)
*/
static void stringFilter(char[] input, long len, char[] output) {
boolean[] seen = new boolean[26]; // a-z
int outIdx = 0;
for (int i = 0; i < len; i++) {
int idx = input[i] - 'a';
if (!seen[idx]) {
seen[idx] = true;
output[outIdx++] = input[i];
}
}
// 其餘位置可不處理,呼叫端依 outIdx 判斷有效長度
}
規則:僅壓縮連續重複字元,格式為 次數+字元;次數為 1 時省略次數。
範例:"xxxyyyyyyz" → "3x6yz"、"abcbc" → "abcbc"、"cccddecc" → "3c2de2c"
/**
* 字串壓縮:連續重複編碼為 次數+字元
* @param input 輸入字元陣列
* @param len 有效長度
* @param output 輸出緩衝區(呼叫端預分配,建議 2*len)
*/
static void stringZip(char[] input, long len, char[] output) {
if (len == 0) return;
char prev = input[0];
int count = 1;
int outIdx = 0;
for (int i = 1; i < len; i++) {
if (input[i] == prev) {
count++;
} else {
// 輸出前一組
if (count > 1) {
output[outIdx++] = (char) ('0' + count); // 單位數;超過 9 需多位數處理
}
output[outIdx++] = prev;
prev = input[i];
count = 1;
}
}
// 處理最後一組
if (count > 1) output[outIdx++] = (char) ('0' + count);
output[outIdx++] = prev;
}
public class StringAlgorithmTest {
public static void main(String[] args) {
char[] test = {'a','a','a','c','b','b','b','a','a','c','a','d','d','d','c','d','e'};
long len = test.length;
// 去重測試
char[] filterOut = new char[(int) len];
stringFilter(test, len, filterOut);
System.out.print("去重結果: ");
for (char c : filterOut) if (c != 0) System.out.print(c);
System.out.println();
// 壓縮測試
char[] zipOut = new char[(int) (2 * len)];
stringZip(test, len, zipOut);
System.out.print("壓縮結果: ");
for (char c : zipOut) if (c != 0) System.out.print(c);
System.out.println();
}
// 將上述 stringFilter、stringZip 方法放在此處
}
| 演算法 | 時間複雜度 | 空間複雜度 | 備註 |
|---|---|---|---|
| 去重 | O(n) | O(1) 固定 26 boolean | 單趟掃描,原地可行 |
| 壓縮 | O(n) | O(1) 常數額外空間 | 單趟掃描,輸出緩衝區不算額外空間 |
String.valueOf(count))。seen 陣列需改用 Set<Character> 或位圖。Reader/Writer 串流式處理,不載入全文。