报数
报数序列是一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下:
-
1
-
11
-
21
-
1211
-
111221
1 被读作 “one 1” (“一个一”) , 即 11。
11 被读作 “two 1s” (“两个一”), 即 21。
21 被读作 “one 2”, “one 1” (“一个二” , “一个一”) , 即 1211。
给定一个正整数 n(1 ≤ n ≤ 30),输出报数序列的第 n 项。
注意:整数顺序将表示为一个字符串。
示例 1:
输入: 1
输出: “1”
示例 2:
输入: 4
输出: “1211”
class Solution {
public String countAndSay(int n) {
/*
统计连续出现数字个数,和当前的数字组成新的字符串
定义快慢指针i,j,和重复出现的字符个数
如果i,j位置元素相等,则j++,cnt++
否则,sb.append(cnt +""+ pre.charAt(i)),即记录到当前字符串中
时间O(n),空间O(n)
*/
ArrayList<String> strs = new ArrayList<>();
strs.add(Integer.toString(1));
for (int k = 1; k < n; k++){
String pre = strs.get(k-1);
StringBuffer sb = new StringBuffer();
int i = 0, j = 0;
int cnt = 0;
while(j < pre.length()){
if(pre.charAt(i) == pre.charAt(j)){
cnt++;
j++;
}else{
sb.append(cnt +""+ pre.charAt(i));
i = j;
cnt = 0;
}
}
if(cnt != 0){
//有可能cnt不为0,说明当前还有字符没有加到sb中
sb.append(cnt + "" +pre.charAt(i));
}
strs.add(sb.toString());
}
return strs.get(strs.size()-1);
}
}
优化代码
class Solution {
public String countAndSay(int n) {
/*
* 记录当前字符重复的数量
* 注意这种找重复字符,并记录数量的方式
* */
ArrayList<String> strs = new ArrayList<>();
strs.add(Integer.toString(1));
for (int k = 1; k < n; k++){
String pre = strs.get(k-1);
StringBuffer sb = new StringBuffer();
int i = 0, j = 0;
while (j < pre.length()){
if(j + 1 == pre.length() || pre.charAt(j) != pre.charAt(j+1)){
sb.append((j-i+1)+""+pre.charAt(i));
i = j + 1;
}
j++;
}
strs.add(sb.toString());
}
return strs.get(strs.size()-1);
}
}
压缩字符串
给定一组字符,使用原地算法将其压缩。
压缩后的长度必须始终小于或等于原数组长度。
数组的每个元素应该是长度为1 的字符(不是 int 整数类型)。
在完成原地修改输入数组后,返回数组的新长度。
进阶:
你能否仅使用O(1) 空间解决问题?
示例 1:
输入:
[“a”,“a”,“b”,“b”,“c”,“c”,“c”]
输出:
返回6,输入数组的前6个字符应该是:[“a”,“2”,“b”,“2”,“c”,“3”]
说明:
"aa"被"a2"替代。"bb"被"b2"替代。"ccc"被"c3"替代。
示例 2:
输入:
[“a”]
输出:
返回1,输入数组的前1个字符应该是:[“a”]
说明:
没有任何字符串被替代。
示例 3:
输入:
[“a”,“b”,“b”,“b”,“b”,“b”,“b”,“b”,“b”,“b”,“b”,“b”,“b”]
输出:
返回4,输入数组的前4个字符应该是:[“a”,“b”,“1”,“2”]。
说明:
由于字符"a"不重复,所以不会被压缩。"bbbbbbbbbbbb"被“b12”替代。
注意每个数字在数组中都有它自己的位置。
class Solution {
public int compress(char[] chars) {
/*
快慢指针法
快慢指针i,j,相同字符数量cnt
i和j位置值相同时,cnt++,j往后一部
否则,将当前的cnt和字符按规则添加到sb中
最后转换成字符数组即可
时间O(n)空间O(n)
*/
StringBuffer sb = new StringBuffer();
int i = 0,j = 0, cnt = 0;
int len = chars.length;
while (j < len){
if(chars[i] == chars[j]){
cnt++;
j++;
}else {
if (cnt > 1) {
sb.append(chars[i] + "" + cnt);
} else if (cnt == 1) {
sb.append(chars[i]);
}
cnt = 0;
i = j;
}
}
if(cnt > 1){
sb.append(chars[i] + "" + cnt);
}else if(cnt == 1) {
sb.append(chars[i]);
}
char []tmp = sb.toString().toCharArray();
for (int k = 0; k < tmp.length; k++){
chars[k] = tmp[k];
// System.out.printf("%c ", chars[k]);
}
return tmp.length;
}
}
class Solution {
public int compress(char[] chars) {
/*
快慢指针i,j
w为写入指针
j遍历字符数组,相同的元素跳过,当前元素和后一个元素不相同时或者j就在最后一个元素时
要将i位置的字符写入,并且当j>i时,在写入相同元素的个数
i移动到j+1的位置
时间O(n),空间O(1)
*/
int i = 0, j = 0, w = 0;
while(j < chars.length){
if(j + 1 == chars.length || chars[j] != chars[j+1] ){
chars[w++] = chars[i];
if(j > i){
for(char c :(""+(j-i+1)).toCharArray()){
chars[w++] = c;
}
}
i = j + 1;
}
j++;
}
return w;
}
}
上述两题操作类似。