Skip to content

Commit 80312f6

Browse files
author
binbin.hou
committed
[Feature] add for new
1 parent 0263d87 commit 80312f6

File tree

1 file changed

+307
-0
lines changed

1 file changed

+307
-0
lines changed
Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
---
2+
title: LC443. 压缩字符串 string-compression
3+
date: 2025-08-31
4+
categories: [Leetcode-75]
5+
tags: [leetcode, Leetcode-75, string]
6+
published: true
7+
---
8+
9+
# LC443. 压缩字符串 string-compression
10+
11+
给你一个字符数组 chars ,请使用下述算法压缩:
12+
13+
从一个空字符串 s 开始。对于 chars 中的每组 连续重复字符 :
14+
15+
如果这一组长度为 1 ,则将字符追加到 s 中。
16+
否则,需要向 s 追加字符,后跟这一组的长度。
17+
压缩后得到的字符串 s 不应该直接返回 ,需要转储到字符数组 chars 中。需要注意的是,如果组长度为 10 或 10 以上,则在 chars 数组中会被拆分为多个字符。
18+
19+
请在 修改完输入数组后 ,返回该数组的新长度。
20+
21+
你必须设计并实现一个只使用常量额外空间的算法来解决此问题。
22+
23+
注意:数组中超出返回长度的字符无关紧要,应予忽略。
24+
25+
26+
27+
示例 1:
28+
29+
输入:chars = ["a","a","b","b","c","c","c"]
30+
输出:返回 6 ,输入数组的前 6 个字符应该是:["a","2","b","2","c","3"]
31+
解释:"aa" 被 "a2" 替代。"bb" 被 "b2" 替代。"ccc" 被 "c3" 替代。
32+
示例 2:
33+
34+
输入:chars = ["a"]
35+
输出:返回 1 ,输入数组的前 1 个字符应该是:["a"]
36+
解释:唯一的组是“a”,它保持未压缩,因为它是一个字符。
37+
示例 3:
38+
39+
输入:chars = ["a","b","b","b","b","b","b","b","b","b","b","b","b"]
40+
输出:返回 4 ,输入数组的前 4 个字符应该是:["a","b","1","2"]
41+
解释:由于字符 "a" 不重复,所以不会被压缩。"bbbbbbbbbbbb" 被 “b12” 替代。
42+
43+
44+
提示:
45+
46+
1 <= chars.length <= 2000
47+
chars[i] 可以是小写英文字母、大写英文字母、数字或符号
48+
49+
50+
51+
# v1-借助空间
52+
53+
## 思路
54+
55+
首先借助额外空间,实现这个基本的特性。
56+
57+
这里主要是理解题意就行,原始的 chars 需要进行处理,然后返回的是需要关注的长度。
58+
59+
## 实现
60+
61+
```java
62+
public int compress(char[] chars) {
63+
int n = chars.length;
64+
if(n == 1) {
65+
return 1;
66+
}
67+
68+
StringBuilder buffer = new StringBuilder();
69+
70+
char pre = chars[0];
71+
int count = 1;
72+
// 遍历
73+
for(int i = 1; i < n; i++) {
74+
char c = chars[i];
75+
76+
77+
78+
// 最后一个
79+
if(i == n-1) {
80+
if(c != pre) {
81+
buffer.append(pre);
82+
if(count > 1) {
83+
buffer.append(count);
84+
}
85+
buffer.append(c);
86+
} else {
87+
// 相同
88+
count++;
89+
buffer.append(c);
90+
buffer.append(count);
91+
}
92+
} else {
93+
// 不是最后一个
94+
// 不相等,则前面的信息入库
95+
if(c != pre) {
96+
buffer.append(pre);
97+
if(count > 1) {
98+
buffer.append(count);
99+
}
100+
count = 1;
101+
} else {
102+
count++;
103+
}
104+
}
105+
106+
pre = c;
107+
}
108+
109+
for(int i = 0; i < buffer.length(); i++) {
110+
chars[i] = buffer.charAt(i);
111+
}
112+
113+
return buffer.length();
114+
}
115+
```
116+
117+
118+
## 效果
119+
120+
1ms 击败 81.36%
121+
122+
## 复杂度
123+
124+
TC: O(n)
125+
126+
SC: O(n)
127+
128+
## 反思
129+
130+
我们是否存在一种方法,可以只使用常量空间呢
131+
132+
# v2-使用常量的空间
133+
134+
## 思路
135+
136+
这种一般大概率就是指针来解决。
137+
138+
整体实现和上上面类似,我们用 left + right 两个指针。
139+
140+
left=right=0;
141+
142+
right 像普通的遍历一样,left 则对应的是结果真实的位置。
143+
144+
返回值:left
145+
146+
## 实现
147+
148+
```java
149+
public int compress(char[] chars) {
150+
int n = chars.length;
151+
if(n == 1) {
152+
return 1;
153+
}
154+
155+
156+
char pre = chars[0];
157+
int count = 1;
158+
int left = 0;
159+
// 遍历
160+
for(int right = 1; right < n; right++) {
161+
char c = chars[right];
162+
163+
// 最后一个
164+
if(right == n-1) {
165+
if(c != pre) {
166+
chars[left++] = pre;
167+
if(count > 1) {
168+
left = appendCount(chars, left, count);
169+
}
170+
chars[left++] = c;
171+
} else {
172+
// 相同
173+
count++;
174+
chars[left++] = c;
175+
left = appendCount(chars, left, count);
176+
}
177+
} else {
178+
// 不是最后一个
179+
// 不相等,则前面的信息入库
180+
if(c != pre) {
181+
chars[left++] = pre;
182+
if(count > 1) {
183+
left = appendCount(chars, left, count);
184+
}
185+
count = 1;
186+
} else {
187+
count++;
188+
}
189+
}
190+
191+
pre = c;
192+
}
193+
194+
195+
return left;
196+
}
197+
198+
// 也可以用除法加入
199+
private int appendCount(char[] chars, int left, int count) {
200+
String countStr = count+"";
201+
for(int i = 0; i < countStr.length(); i++) {
202+
chars[left++] = countStr.charAt(i);
203+
}
204+
205+
return left;
206+
}
207+
```
208+
209+
## 效果
210+
211+
1ms 击败 81.36%
212+
213+
## 复杂度
214+
215+
TC: O(n)
216+
217+
SC: O(1)
218+
219+
# v3-优化
220+
221+
## 最后一个字符的优化
222+
223+
其实我们可以针对最后一个判断稍微优化下,看起来代码简单一些
224+
225+
```java
226+
public int compress(char[] chars) {
227+
int n = chars.length;
228+
if(n == 1) {
229+
return 1;
230+
}
231+
232+
233+
char pre = chars[0];
234+
int count = 1;
235+
int left = 0;
236+
// 遍历
237+
for(int right = 1; right < n; right++) {
238+
char c = chars[right];
239+
240+
// 不相等,则前面的信息入库
241+
if(c != pre) {
242+
chars[left++] = pre;
243+
if(count > 1) {
244+
left = appendCount(chars, left, count);
245+
}
246+
count = 1;
247+
} else {
248+
count++;
249+
}
250+
251+
pre = c;
252+
}
253+
254+
// 最后一个
255+
chars[left++] = pre;
256+
if(count > 1) {
257+
left = appendCount(chars, left, count);
258+
}
259+
260+
261+
return left;
262+
}
263+
264+
// 也可以用除法加入
265+
private int appendCount(char[] chars, int left, int count) {
266+
String countStr = count+"";
267+
for(int i = 0; i < countStr.length(); i++) {
268+
chars[left++] = countStr.charAt(i);
269+
}
270+
271+
return left;
272+
}
273+
```
274+
275+
## appendCount 改写
276+
277+
可以考虑这样写,这样避免 string 对象的创建,性能会好一些。
278+
279+
通过除法,获取逆序数字,然后 reverse
280+
281+
```java
282+
private int appendCount(char[] chars, int left, int count) {
283+
// 先把数字倒着写,再反转
284+
int start = left;
285+
while (count > 0) {
286+
chars[left++] = (char) ('0' + (count % 10));
287+
count /= 10;
288+
}
289+
// 翻转刚写的数字部分
290+
reverse(chars, start, left - 1);
291+
return left;
292+
}
293+
294+
private void reverse(char[] chars, int l, int r) {
295+
while (l < r) {
296+
char tmp = chars[l];
297+
chars[l++] = chars[r];
298+
chars[r--] = tmp;
299+
}
300+
}
301+
```
302+
303+
### 效果
304+
305+
0ms 100%
306+
307+
# 参考资料

0 commit comments

Comments
 (0)