数据结构与算法
task05
1.无重复字符的最长字符
思路都在注释里了
public int lengthOfLongestSubstring(String s) {
//如果s为空,length不大于0,是一个空串,就没有向下执行的必要了
if(s != null && s.length() > 0 && s != ""){
//String -> char[]
char[] strChar = s.toCharArray();
// 存储最长字串 key:char值,value:index下标
ArrayList<String> maxStr = new ArrayList<>();
//临时的字串存储空间
ArrayList<String> tempStr = new ArrayList<>();
//循环
for(int i=0; i<strChar.length; i++){
//char -> String
String str = new String(new char[]{strChar[i]});
//判断str是否存在于tempStr中
if(tempStr.contains(str)){
//先判断tempStr的长度是否大于等于maxStr的长度,大于,才能将最长字串覆盖
if(tempStr.size() > maxStr.size()){
maxStr = new ArrayList<>(tempStr);
}
//存储重复字符
int reIndex = tempStr.indexOf(str);
// 删除tempStr中的重复字节及其之前的字符
for(int j=0;j<=reIndex;j++){
tempStr.remove(0);
}
}
//将当前字符存入tempStr中
tempStr.add(str);
}
//最终判断
if(tempStr.size() > maxStr.size()){
maxStr = tempStr;
}
//返回最长字串的长度
return maxStr.size();
}
return 0;
}
2.串联所有单词的子串
参考了leetcode的题解,思路很清晰,用了滑动窗口。
模拟了一个最大长度为给定单词长度之和的滑块(words.length * len)。让滑块在字符串S上滑动,通过判定滑块捏的字符是否匹配给定单词来存储下标。 然后做了一些优化处理。
1.首先我缓存了所有words中个word 在字符S中的下标。在后续比较中直接比较map,减少循环次数。
2.滑块每次滑动的长度为单词的长度 len。这样滑块中间的数据不用重复比较。滑块分别从下标 0 到len-1共循环滑动 len次。
3.下标为0时,滑块判定的数据为 0, len , 2 * len, 3*len…
4.下标为1时,滑块判定的数据为 1,len +1, 2 len+1 ,3len+1…
5.循环构建滑块,从map中缓存在下标开始构建,当滑动到不在map中的单词时,销毁滑块。直到下一个有效下标重新构建。
6.在滑动滑块的过程中,记录滑块内有效的单词个数 flagNum.每次滑动后。7.如果有效的单词个数与总单词个数相同,时滑块内的数据就是我们所要的。
public static List<Integer> findSubstring(String s, String... words) {
`List<Integer> list = new ArrayList<>();
if (s.length() == 0 || words.length == 0)
return list;
int len = words[0].length();
if (s.length() < words.length * len)
return list;
int idx = -1;
char[] sCharS = s.toCharArray();
Set<Integer> allSet = new HashSet<Integer>();// 存储在字符串S所有匹配的下标 去重 排序
Map<String, Integer> wordMap = new HashMap<>();// 存储 word中各个单词的个数
Map<Integer, String> idxMap = new HashMap<>();// 存储字符串s各下标对应的单词
for (String word : words) {
if (wordMap.containsKey(word)) {
wordMap.put(word, wordMap.get(word) + 1);
continue;
}
char[] tem = word.toCharArray();
while ((idx = indexOf(sCharS, sCharS.length, tem, len, idx + 1)) > -1) {
idxMap.put(idx, word);
allSet.add(idx);
}
wordMap.put(word, 1);
}
String word;
int slideLen = len * words.length;// 滑块长度
int n;// 临时变量
Map<String, Integer> temWordMap = new HashMap<>();
for (int k = 0; k < len; k++) {
int flagNum = 0;// 表示滑块中有效的单词个数
for (int i = -1, j = k; j <= sCharS.length - len; j += len) {
if (allSet.contains(j)) {
if (i == -1) {// 初始化滑块
i = j;
flagNum = 0;
temWordMap.clear();
temWordMap.putAll(wordMap);
}
// 滑块长度增加 在尾部添加
word = idxMap.get(j);
n = temWordMap.get(word) - 1;
temWordMap.put(word, n);
if (n >= 0)
flagNum++;
if (j - i >= slideLen) {// 滑块长度减小 吐出头部数据
word = idxMap.get(i);
n = temWordMap.get(word) + 1;
temWordMap.put(word, n);
if (n > 0)
flagNum--;
i += len;
}
if (flagNum == words.length)
list.add(i);
} else {
i = -1;// j所在的位置不是给定的单词 ,销毁滑块
}
}
}
return list;
}
3.替换子串得到平衡字符串
应用了滑动窗口
public int balancedString(String s) {
int q = 0;
int w = 0;
int e = 0;
int r = 0;
int begin = 0;
int cur = 0;
int res = 100000;
int len = s.length();
while(cur<len){
if(s.charAt(cur)=='Q')
q++;
else if(s.charAt(cur)=='W')
w++;
else if(s.charAt(cur)=='E')
e++;
else
r++;
cur++;
}
if(q==w && w==e && e==r)
return 0;
cur=0;
while(cur<len){
if(s.charAt(cur)=='Q')
q--;
else if(s.charAt(cur)=='W')
w--;
else if(s.charAt(cur)=='E')
e--;
else
r--;
while(q<=len/4 &&w<=len/4 &&e<=len/4 &&r<=len/4 &&begin<=cur){
res = Math.min(res,cur-begin+1);
if(s.charAt(begin)=='Q')
q++;
else if(s.charAt(begin)=='W')
w++;
else if(s.charAt(begin)=='E')
e++;
else
r++;
begin++;
}
cur++;
}
return res;
}