day15(11.15)——leetcode面试经典150
30. 串联所有单词的子串
30.串联所有单词的子串
题目:



题解:
这是我一开始写的,我想的是通过组合排列的方式进行拼接好所有字符串,然后再一个一个判断在s中能否找到,这样内存直接爆了我服了哈哈哈哈哈
import java.util.*;class Solution {public List<Integer> findSubstring(String s, String[] words) {if (words == null || words.length == 0 || s.isEmpty()) {return new ArrayList<>();}// 每次调用都创建新的局部变量,避免全局污染!List<String> list = new ArrayList<>();StringBuilder ls = new StringBuilder();boolean[] bs = new boolean[words.length];// 生成所有唯一排列(注意:words 可能有重复,需去重)dfs(0, bs, words, ls, list);// 去重(因为 words 可能有重复元素,如 ["bar","bar"])Set<String> uniqueSet = new LinkedHashSet<>(list);List<Integer> result = new ArrayList<>();for (String concat : uniqueSet) {int index = s.indexOf(concat);while (index != -1) {result.add(index);index = s.indexOf(concat, index + 1); // 修复:+1 避免死循环!}}return result;}private void dfs(int depth, boolean[] used, String[] words, StringBuilder path, List<String> result) {if (depth == words.length) {result.add(path.toString());return;}for (int i = 0; i < words.length; i++) {if (!used[i]) {used[i] = true;path.append(words[i]);dfs(depth + 1, used, words, path, result);path.delete(path.length() - words[i].length(), path.length());used[i] = false;}}}
}
然后就换了一个方法,用双指针+哈希map进行计数:
class Solution {public List<Integer> findSubstring(String s, String[] words) {List<Integer> res = new ArrayList<>();//进行特判//字符串不可能为nullif(s.length() == 0 || words == null || words.length == 0 ) {return res;}//进行设置变量:每个单词的长度、单词的个数、拼接好的字符串的长度//每个单词的长度int wordLen = words[0].length();//单词的个数int len = words.length;//拼接好的字符串的长度int wordsLen = len*wordLen;//设计map进行统计每个单词出现的次数Map<String,Integer> map = new HashMap<>();for(String word:words) {map.put(word,map.getOrDefault(word, 0)+1);}//滑动窗口进行设置//外层循环 for (int i = 0; i < wordLen; i++) 的作用:处理对齐问题for(int i=0;i<wordLen;i++) {//设置左右边界int left=i,right=i;//创建一个新的统计map序列Map<String,Integer> mp = new HashMap<>();while(right+wordLen<=s.length()) {//截取当前得到的单词String str = s.substring(right,right+wordLen);//更新right的位置right+=wordLen;//在map中不存在strif(!map.containsKey(str)) {// 说明一整个序列都不符合mp.clear();// 直接跳过这个序列left = right;}//当前截取的str在map中存在else {//进行统计单词频数mp.put(str, mp.getOrDefault(str, 0)+1);//进行判断当前的mp各个单词的数量是否超过数组中统计的mapwhile(map.get(str)<mp.get(str)) {//直接删去两个重复的,但我们并不确定重复的位置,所以只能从left一直试探String leftWord = s.substring(left,left+wordLen);mp.put(leftWord, mp.getOrDefault(leftWord,0)-1);// 进行更新leftleft+=wordLen;}}if(right-left == wordsLen) {res.add(left);}}}return res;}
}
