删除多余字符得到字典序最小的字符串
《程序员代码面试指南》第86题 P276 难度:尉★★☆☆
不太好做的题。。
概括一下思路,根据字频统计,遍历str时找到一个前缀str[0..R](遍历到字符的字频减1,某一种字符的字频统计为0时,停止遍历),然后在str[0..R]中找到最小ASCII码的字符str[X]。然后令str=(str[X+1..R]去掉所有str[X]得到的字符串),重复整个过程,找到结果字符串的下一个字符,直到res生成完毕。每找到一个res[i],都要重新建立字频统计以及在整个字符串中删除已经找到的字符,所以时间复杂度为O(K×N)。又因为str中都是小写字母,K不会超过26,所以时间复杂度为O(N)。
详细步骤举例见书P277,下面是代码:
public String removeDuplicateLetters(String s) {
char[] str = s.toCharArray();
// 小写字母ascii码值范围[97~122],所以用长度为26的数组做次数统计
// 如果map[i] > -1,则代表ascii码值为i的字符的出现次数
// 如果map[i] == -1,则代表ascii码值为i的字符不再考虑
int[] map = new int[26];
for (int i = 0; i < str.length; i++) {
map[str[i] - 'a']++;
}
char[] res = new char[26];
int index = 0;
int L = 0;
int R = 0;
while (R != str.length) {
// 如果当前字符是不再考虑的,直接跳过
// 如果当前字符的出现次数减1之后,后面还能出现,直接跳过
if (map[str[R] - 'a'] == -1 || --map[str[R] - 'a'] > 0) {
R++;
} else { // 当前字符需要考虑并且之后不会再出现了
// 在str[L..R]上所有需要考虑的字符中,找到ascii码最小字符的位置
int pick = -1;
for (int i = L; i <= R; i++) {
if (map[str[i] - 'a'] != -1 && (pick == -1 || str[i] < str[pick])) {
pick = i;
}
}
// 把ascii码最小的字符放到挑选结果中
res[index++] = str[pick];
// 在上一个的for循环中,str[L..R]范围上每种字符的出现次数都减少了
// 需要把str[pick + 1..R]上每种字符的出现次数加回来
for (int i = pick + 1; i <= R; i++) {
if (map[str[i] - 'a'] != -1) { // 只增加以后需要考虑字符的次数
map[str[i] - 'a']++;
}
}
// 选出的ascii码最小的字符,以后不再考虑了
map[str[pick] - 'a'] = -1;
// 继续在str[pick + 1......]上重复这个过程
L = pick + 1;
R = L;
}
}
return String.valueOf(res, 0, index);
}
标签:字符,26,map,int,str,字符串,字典 来源: https://www.cnblogs.com/CWZhou/p/16182758.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。