找到字符串的最长无重复字符子串 & 字符串的统计字符串
找到字符串的最长无重复字符子串
《程序员代码面试指南》第94题 P300 难度:尉★★☆☆
首先是几个变量的介绍:哈希表map,key表示某个字符,value为这个字符最近一次出现的位置。整型变量pre,如果当前遍历到字符str[i],pre表示在必须以str[i-1]字符结尾的情况下,最长无重复字符子串开始位置的前一个位置,初始时pre=-1。整型变量len,记录以每一个字符结尾的情况下,最长无重复字符子串长度的最大值,初始时,len=0。从左到右依次遍历str,假设现在遍历到str[i],接下来求在必须以str结尾的情况下,最长无重复字符子串的长度。
map(str[i])的值表示之前的遍历中最近一次出现str字符的位置,假设在a位置。想要求以str[i]结尾的最长无重复子串,a位置必然不能包含进来,因为str[a]等于str[i]。
根据pre的定义,pre+1表示在必须以str[i-1]字符结尾的情况下,最长无重复字符子串的开始位置。也就是说,以str[i-1]结尾的最长无重复子串是向左扩到pre位置停止的。
如果pre位置在a位置的左边,因为str[a]不能包含进来,而str[a+1..i-1]上都是不重复的,所以以str[i]结尾的最长无重复字符子串就是str[a+1..i]。如果pre位置在a位置的右边,以str[i-1]结尾的最长无重复子串是向左扩到pre位置停止的。所以以str[i]结尾的最长无重复子串向左扩到pre位置也必然会停止,而且str[pre+1..i-1]这一段上肯定不含有str[i],所以以str[i]结尾的最长无重复字符子串就是str[pre+1..i]。
计算完长度之后,pre位置和a位置哪一个在右边,就作为新的pre值。然后计算下一个位置的字符,整个过程中求得所有长度的最大值用len记录下来返回即可。
具体请参看如下代码中的maxUnique方法。
public int maxUnique(String str) {
if (str == null || str.equals("")) {
return 0;
}
char[] chas = str.toCharArray();
int[] map = new int[256];
for (int i = 0; i < 256; i++) {
map[i] = -1;
}
int len = 0;
int pre = -1;
int cur = 0;
for (int i = 0; i != chas.length; i++) {
pre = Math.max(pre, map[chas[i]]);
cur = i - pre;
len = Math.max(len, cur);
map[chas[i]] = i;
}
return len;
}
字符串的统计字符串
题目:字符串的统计字符串
《程序员代码面试指南》第80题 P258 难度:士★☆☆☆
这题没什么含金量,逐个遍历,str[i]==str[i-1]就num++,否则拼接字符串。注意在遍历完成后还需要再拼接上最后一种字符的次数。不多说,直接看代码:
public String getCountString(String str) {
if (str == null || str.equals("")) {
return "";
}
char[] chs = str.toCharArray();
String res = String.valueOf(chs[0]);
int num = 1;
for (int i = 1; i < chs.length; i++) {
if (chs[i] != chs[i - 1]) {
res = concat(res, String.valueOf(num), String.valueOf(chs[i]));
num = 1;
} else {
num++;
}
}
return concat(res, String.valueOf(num), "");
}
public String concat(String s1, String s2, String s3) {
return s1 + "_" + s2 + (s3.equals("") ? s3 : "_" + s3);
}
(个人觉得用StringBuilder效率更高一点)
进阶问题:
public char getCharAt(String cstr, int index) {
if (cstr == null || cstr.equals("")) {
return 0;
}
char[] chs = cstr.toCharArray();
boolean stage = true;
char cur = 0;
int num = 0;
int sum = 0;
for (int i = 0; i != chs.length; i++) {
if (chs[i] == '_') {
stage = !stage;
} else if (stage) {
sum += num;
if (sum > index) {
return cur;
}
num = 0;
cur = chs[i];
} else {
num = num * 10 + chs[i] - '0';
}
}
return sum + num > index ? cur : 0;
}
书上的方法很繁琐,我的方法是通过split("_")分割字符串,分割后索引为奇数1、3、5…的字符串通过Integer.parseInt()转化后就是各个字符的次数,直接去统计就行,不需要像书上这样还挨个num=num*10+chs[i]去计算次数。。

浙公网安备 33010602011771号