📘 題目敘述
給定一個字元陣列 chars,請你使用 原地(in-place) 的方式壓縮它。
壓縮規則:
- 對於每一段連續重複的字元:
- 先寫入該字元
- 若該字元連續出現的次數大於
1,再把次數(以字元形式)依序寫入 - 例如
12會寫成'1'、'2'
- 最後回傳壓縮後的新長度
- 你必須在輸入陣列
chars上直接修改內容,且只能使用 常數額外空間。
條件限制
1 ≤ chars.length ≤ 2000chars[i]是小寫英文字母、大寫英文字母、數字或符號
🧠 解題思路
我用的是「一邊掃描原本的 chars,一邊把壓縮結果寫回 chars 前面」的做法。
核心概念是:
- 用
now記錄「目前這一段在統計的字元是誰」 - 用
count記錄「這個字元連續出現了幾次」 - 用
all當作「寫入指標」:壓縮後的內容都寫回chars[0..all-1]
一旦遇到新字元(chars[i] != now):
- 代表上一段結束,要把上一段的
count(如果 > 1)寫回去 - 再開始新的段落
最後迴圈跑完後,還要把「最後一段」補寫一次(因為不會再遇到新字元觸發結算)。
所有變數
all:寫入位置(壓縮後結果寫回chars[all],寫完就all++)count:目前這一段連續出現的次數now:目前正在統計的字元(上一段的代表字元)i:掃描原始chars的索引s:把count轉成字串後的結果(例如12 -> "12"),用來逐字寫入
🪜 主要流程步驟
1. 掃描 chars,偵測「段落」的切換
- 我從左到右掃描
chars[i] - 如果
chars[i] != now,代表:- 上一段結束
- 新的一段開始
2. 當遇到新字元時:先結算上一段,再開始新段
當 now != chars[i] 時,我做兩件事:
(1) 結算上一段(若 count > 1 才寫數字)
- 把
count用to_string(count)變成字串 - 用
for (char c : s)逐字把'1'、'2'... 寫回chars
for (char c : s)的意思:把字串s裡的每個字元依序取出來,放到變數c。例如s = "12",迴圈會跑兩次:c='1'、c='2'。
(2) 開始新段
- 更新
now = chars[i] - 把這個字元先寫回
chars[all] count = 1(新段剛開始)
3. 當遇到相同字元:只累加次數
- 如果
chars[i] == now - 代表還在同一段
- 我就
count++
4. 迴圈結束後:補寫最後一段的次數
因為最後一段不會再遇到「新字元」來觸發結算,所以要補做一次:
- 若
count > 1,同樣把次數轉成字串,逐字寫回
5. 回傳壓縮後長度
all代表壓縮後寫了多少個字元- 所以直接回傳
all
💻 程式碼實作
class Solution {
public:
int compress(vector<char>& chars) {
int all = 0, count = 0;
char now = ' ';
for (int i = 0; i < chars.size(); i++) {
if (now != chars[i]) {
if (count > 1) {
string s = to_string(count);
for (char c : s) {
chars[all++] = c;
}
}
now = chars[i];
chars[all++] = now;
count = 1;
} else {
count++;
}
}
if (count > 1) {
string s = to_string(count);
for (char c : s) {
chars[all++] = c;
}
}
return all;
}
};