1、题目描述
给定一个字符串str,现在要对该字符串进行删除操作,保留字符串中的k个字符且相对位置不变,并且使它的字典序最小,返回这个子串。
例一
输入:str=“fskacsbi”,k=2
输出:“ab”
解释:“ab“是str中长度为2并且字典序最小的子串
例二
输入:str=“fsakbacsi”,k=3
输出:“aac”
2、代码
首先我要说明,我的思路是参考了LintCode用户marshall给出的解决方案,题目链接。我自己也思考了很久这道题的解法,当做记录。
public class Solution {
/**
* @param str: the string
* @param k: the length
* @return: the substring with the smallest lexicographic order
*/
public String deleteChar(String str, int k) {
//目的是让子串的字典序最小
int n = str.length();
char[] result = new char[k];
char[] list = str.toCharArray();
for(int i = n-k;i < n;i++){
result[i-(n-k)] = list[i];
}
for(int i = n-k-1;i >=0 ;i--){
for(int j = 0;j < k;j++){
//注意list和result的字符交换的同时字符见的相对位置也发生了变化
if(list[i] < result[j]){
char temp = result[j];
result[j] = list[i];
list[i] = temp;
}else if(list[i] > result[j]){
break;
}
}
}
return String.valueOf(result);
}
}
3、自己的想法
我看网上好像没有解析呀~当前阶段果然还是菜菜子hhh。首先这道题要明白什么是字典序,字典序的原意是表示英文单词在字典中的先后顺序,在计算机领域中扩展成两个任意字符串的大小关系。对于两个任意的字符串,其大小关系取决于两个字符串从左到右第一个不同字符的 ASCII 值的大小关系。
我们知道,每一个char对应着一个int,所以我先通过toCharArray()的方法把String转换为字符char。注意,题目要求的是字符串中的k个字符且相对位置不变,并且使它的字典序最小。第二个要关注的重点是,相对位置不变。看到这个问题,我第一个想法是嵌套k个for循环,这当然不可能pass。所以初始化的时候要分成两个数组,一个就是由String转为char的数组list;另一个是result,取自原数组list的倒数k个数。这样做的好处是,保证我们的结果数组result是按照原字符串str中的字符是从左到右按照顺序排列的。
接下来是外层的for循环,是从list的右往左进行遍历的,举个例子:现有字符(我直接用数字表示大小)按照以下顺序排列 4,1,7,8,n = 4,k = 2:
1. 7,1,4,8
2. 8,1,4,7
3. 8,4,1,7
4. 8,7,1,4
最后得到结果1,4,显然按照4,1,7,8的顺序该字符串不存在,正确结果应该为1,7。原因就在于,因为从list从右往左,是不断把位置在右边的更小的字符往result数组右边扔(结合下面的break)。而list左往右,是不断把位置在左边的更小的字符往右边扔,显然会导致顺序颠倒的问题。
1. 4,7,1,8
2. 4,8,1,7
3. 4,8,1,7
接下来就要说上面正确解法的第三步,为什么list[i] > result[j]之后要break。同理,也是为了防止result中字符顺序颠倒。要保证result[i]的一定在result[i+1]的左边,如果不break,就会出现某个list[m]存在result[i]<list[m]<result[i+1],而list[m]字符的顺序在result[i]的左边。
PS:有错误希望能指正,觉得不错请给个赞吧,谢谢~