给你一个字符数组 chars
,请使用下述算法压缩:
从一个空字符串 s
开始。对于 chars
中的每组 连续重复字符 :
- 如果这一组长度为
1
,则将字符追加到 s
中。
- 否则,需要向
s
追加字符,后跟这一组的长度。
压缩后得到的字符串 s
不应该直接返回 ,需要转储到字符数组 chars
中。需要注意的是,如果组长度为 10
或 10
以上,则在
chars
数组中会被拆分为多个字符。
请在 修改完输入数组后 ,返回该数组的新长度。
你必须设计并实现一个只使用常量额外空间的算法来解决此问题。
示例 1:
**输入:** chars = ["a","a","b","b","c","c","c"]
**输出:** 返回 6 ,输入数组的前 6 个字符应该是:["a","2","b","2","c","3"]
**解释:** "aa" 被 "a2" 替代。"bb" 被 "b2" 替代。"ccc" 被 "c3" 替代。
示例 2:
**输入:** chars = ["a"]
**输出:** 返回 1 ,输入数组的前 1 个字符应该是:["a"]
**解释:** 唯一的组是“a”,它保持未压缩,因为它是一个字符。
示例 3:
**输入:** chars = ["a","b","b","b","b","b","b","b","b","b","b","b","b"]
**输出:** 返回 4 ,输入数组的前 4 个字符应该是:["a","b","1","2"]。
**解释:** 由于字符 "a" 不重复,所以不会被压缩。"bbbbbbbbbbbb" 被 “b12” 替代。
提示:
1 <= chars.length <= 2000
chars[i]
可以是小写英文字母、大写英文字母、数字或符号
方法一:双指针
思路和算法
为了实现原地压缩,我们可以使用双指针分别标志我们在字符串中读和写的位置。每次当读指针 read 移动到某一段连续相同子串的最右侧,我们就在写指针 write 处依次写入该子串对应的字符和子串长度即可。
在实际代码中,当读指针 read 位于字符串的末尾,或读指针 read 指向的字符不同于下一个字符时,我们就认为读指针 read 位于某一段连续相同子串的最右侧。该子串对应的字符即为读指针 read 指向的字符串。我们使用变量 left 记录该子串的最左侧的位置,这样子串长度即为 read} - \textit{left} + 1$。
特别地,为了达到 $O(1)$ 空间复杂度,我们需要自行实现将数字转化为字符串写入到原字符串的功能。这里我们采用短除法将子串长度倒序写入原字符串中,然后再将其反转即可。
代码
[sol1-C++]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Solution { public: int compress(vector<char>& chars) { int n = chars.size(); int write = 0, left = 0; for (int read = 0; read < n; read++) { if (read == n - 1 || chars[read] != chars[read + 1]) { chars[write++] = chars[read]; int num = read - left + 1; if (num > 1) { int anchor = write; while (num > 0) { chars[write++] = num % 10 + '0'; num /= 10; } reverse(&chars[anchor], &chars[write]); } left = read + 1; } } return write; } };
|
[sol1-Java]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| class Solution { public int compress(char[] chars) { int n = chars.length; int write = 0, left = 0; for (int read = 0; read < n; read++) { if (read == n - 1 || chars[read] != chars[read + 1]) { chars[write++] = chars[read]; int num = read - left + 1; if (num > 1) { int anchor = write; while (num > 0) { chars[write++] = (char) (num % 10 + '0'); num /= 10; } reverse(chars, anchor, write - 1); } left = read + 1; } } return write; }
public void reverse(char[] chars, int left, int right) { while (left < right) { char temp = chars[left]; chars[left] = chars[right]; chars[right] = temp; left++; right--; } } }
|
[sol1-C#]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public class Solution { public int Compress(char[] chars) { int n = chars.Length; int write = 0, left = 0; for (int read = 0; read < n; read++) { if (read == n - 1 || chars[read] != chars[read + 1]) { chars[write++] = chars[read]; int num = read - left + 1; if (num > 1) { int anchor = write; while (num > 0) { chars[write++] = (char) (num % 10 + '0'); num /= 10; } Reverse(chars, anchor, write - 1); } left = read + 1; } } return write; }
public void Reverse(char[] chars, int left, int right) { while (left < right) { char temp = chars[left]; chars[left] = chars[right]; chars[right] = temp; left++; right--; } } }
|
[sol1-C]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| void swap(char *a, char *b) { char t = *a; *a = *b, *b = t; }
void reverse(char *a, char *b) { while (a < b) { swap(a++, --b); } }
int compress(char *chars, int charsSize) { int write = 0, left = 0; for (int read = 0; read < charsSize; read++) { if (read == charsSize - 1 || chars[read] != chars[read + 1]) { chars[write++] = chars[read]; int num = read - left + 1; if (num > 1) { int anchor = write; while (num > 0) { chars[write++] = num % 10 + '0'; num /= 10; } reverse(&chars[anchor], &chars[write]); } left = read + 1; } } return write; }
|
[sol1-Python3]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class Solution: def compress(self, chars: List[str]) -> int: def reverse(left: int, right: int) -> None: while left < right: chars[left], chars[right] = chars[right], chars[left] left += 1 right -= 1
n = len(chars) write = left = 0 for read in range(n): if read == n - 1 or chars[read] != chars[read + 1]: chars[write] = chars[read] write += 1 num = read - left + 1 if num > 1: anchor = write while num > 0: chars[write] = str(num % 10) write += 1 num //= 10 reverse(anchor, write - 1) left = read + 1 return write
|
[sol1-Golang]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| func compress(chars []byte) int { write, left := 0, 0 for read, ch := range chars { if read == len(chars)-1 || ch != chars[read+1] { chars[write] = ch write++ num := read - left + 1 if num > 1 { anchor := write for ; num > 0; num /= 10 { chars[write] = '0' + byte(num%10) write++ } s := chars[anchor:write] for i, n := 0, len(s); i < n/2; i++ { s[i], s[n-1-i] = s[n-1-i], s[i] } } left = read + 1 } } return write }
|
[sol1-JavaScript]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| var compress = function(chars) { const n = chars.length; let write = 0, left = 0; for (let read = 0; read < n; read++) { if (read === n - 1 || chars[read] !== chars[read + 1]) { chars[write++] = chars[read]; let num = read - left + 1; if (num > 1) { const anchor = write; while (num > 0) { chars[write++] = '' + num % 10; num = Math.floor(num / 10); } reverse(chars, anchor, write - 1); } left = read + 1; } } return write; };
const reverse = (chars, left, right) => { while (left < right) { const temp = chars[left]; chars[left] = chars[right]; chars[right] = temp; left++; right--; } }
|
复杂度分析