力扣字符串练习题(串联所有单词的子串、最长有效括号)

73 阅读4分钟

串联所有单词的子串

来源:力扣(LeetCode) 链接:leetcode.cn/problems/su…

给定一个字符串 s 和一个字符串数组 words。 words 中所有字符串 长度相同。

s 中的 串联子串 是指一个包含 words 中所有字符串以任意顺序排列连接起来的子串。

  • 例如,如果 words = ["ab","cd","ef"], 那么 "abcdef", "abefcd","cdabef", "cdefab","efabcd", 和 "efcdab" 都是串联子串。 "acdbef" 不是串联子串,因为他不是任何 words 排列的连接。

返回所有串联字串在 s 中的开始索引。你可以以 任意顺序 返回答案。

示例 1:

输入:s = "barfoothefoobarman", words = ["foo","bar"]

输出:[0,9]

解释:因为 words.length == 2 同时 words[i].length == 3,连接的子字符串的长度必须为 6。

子串 "barfoo" 开始位置是 0。它是 words 中以 ["bar","foo"] 顺序排列的连接。

子串 "foobar" 开始位置是 9。它是 words 中以 ["foo","bar"] 顺序排列的连接。

输出顺序无关紧要。返回 [9,0] 也是可以的。

示例 2:

输入:s = "wordgoodgoodgoodbestword", words = ["word","good","best","word"]

输出:[]

解释:因为 words.length == 4 并且 words[i].length == 4,所以串联子串的长度必须为 16。

s 中没有子串长度为 16 并且等于 words 的任何顺序排列的连接。

所以我们返回一个空数组。

示例 3:

输入:s = "barfoofoobarthefoobarman", words = ["bar","foo","the"]

输出:[6,9,12]

解释:因为 words.length == 3 并且 words[i].length == 3,所以串联子串的长度必须为 9。

子串 "foobarthe" 开始位置是 6。它是 words 中以 ["foo","bar","the"] 顺序排列的连接。

子串 "barthefoo" 开始位置是 9。它是 words 中以 ["bar","the","foo"] 顺序排列的连接。

子串 "thefoobar" 开始位置是 12。它是 words 中以 ["the","foo","bar"] 顺序排列的连接。

提示:

  • 1 <= s.length <= 104
  • 1 <= words.length <= 5000
  • 1 <= words[i].length <= 30
  • words[i] 和 s 由小写英文字母组成

代码

class Solution {
    public List<Integer> findSubstring(String s, String[] words) {
        List<Integer> result = new ArrayList<>();
        if (s.isEmpty() || words.length == 0) {
            return result;
        }
        
        int wordLength = words[0].length();
        int wordCount = words.length;
        int totalLength = wordLength * wordCount;
        
        Map<String, Integer> wordMap = new HashMap<>();
        for (String word : words) {
            wordMap.put(word, wordMap.getOrDefault(word, 0) + 1);
        }
        
        for (int i = 0; i <= s.length() - totalLength; i++) {
            Map<String, Integer> seen = new HashMap<>();
            int j = 0;
            
            while (j < wordCount) {
                String currentWord = s.substring(i + j * wordLength, i + (j + 1) * wordLength);
                if (wordMap.containsKey(currentWord)) {
                    seen.put(currentWord, seen.getOrDefault(currentWord, 0) + 1);
                    if (seen.get(currentWord) > wordMap.get(currentWord)) {
                        break;
                    }
                } else {
                    break;
                }
                
                j++;
            }
            
            if (j == wordCount) {
                result.add(i);
            }
        }
        
        return result;
    }
}

思路分析

  1. 首先判断给定字符串s和单词列表words是否为空。如果其中任意一个为空,则直接返回空结果列表。
  2. 获取单词列表中单词的长度wordLength,以及单词的总个数wordCount和总长度totalLength
  3. 创建一个哈希表wordMap,用于存储单词列表中每个单词出现的次数。
  4. 遍历字符串s的每个可能的起始位置i,从0到s.length() - totalLength
  5. 在每个起始位置i,使用滑动窗口和哈希表来检查子串是否包含指定的单词列表。使用变量j来表示滑动窗口的位置。
  6. 在滑动窗口中,从起始位置i开始,以单词长度为步长,依次取出子串中的单词。
  7. 检查当前单词是否存在于wordMap中。如果存在,更新seen哈希表中当前单词的出现次数,并检查是否超过了在wordMap中的出现次数。
  8. 如果当前单词不在wordMap中,或者当前单词的出现次数超过了在wordMap中的出现次数,终止滑动窗口的移动。

最长有效括号

来源:力扣(LeetCode) 链接:leetcode.cn/problems/lo…

给你一个只包含 '(' 和 ')' 的字符串,找出最长有效(格式正确且连续)括号子串的长度。

示例 1:

输入:s = "(()"

输出:2

解释:最长有效括号子串是 "()"

示例 2:

输入:s = ")()())"

输出:4

解释:最长有效括号子串是 "()()"

示例 3:

输入:s = ""

输出:0

提示:

  • 0 <= s.length <= 3 * 104
  • s[i] 为 '(' 或 ')'

代码

class Solution {
    public int longestValidParentheses(String s) {
        int maxLength = 0;
        Stack<Integer> stack = new Stack<>();
        stack.push(-1);
        
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '(') {
                stack.push(i);
            } else {
                stack.pop();
                if (stack.isEmpty()) {
                    stack.push(i);
                } else {
                    maxLength = Math.max(maxLength, i - stack.peek());
                }
            }
        }
        
        return maxLength;
    }
}

思路分析

  1. 初始化最大长度maxLength为0,并创建一个栈stack,并将-1推入栈中。
  2. 遍历字符串s中的每个字符。
  3. 如果当前字符是'(',将当前字符的下标推入栈中。
  4. 如果当前字符是')',表示遇到了一个可能的有效括号的结尾。我们通过弹出栈顶元素来匹配括号。
  5. 如果栈为空,表示当前')'没有匹配的'(',将当前字符的下标推入栈中作为新的起始点。
  6. 如果栈不为空,计算当前字符的下标与栈顶元素的差值,即为当前有效括号的长度。
  7. 将当前有效括号的长度与最大长度maxLength比较,取较大值作为新的最大长度。
  8. 遍历完字符串后,返回最大长度maxLength