leetcode
leetcode 2551 ~ 2600
找出出现至少三次的最长特殊子字符串 I

找出出现至少三次的最长特殊子字符串 I

难度:

标签:

题目描述

You are given a string s that consists of lowercase English letters.

A string is called special if it is made up of only a single character. For example, the string "abc" is not special, whereas the strings "ddd", "zz", and "f" are special.

Return the length of the longest special substring of s which occurs at least thrice, or -1 if no special substring occurs at least thrice.

A substring is a contiguous non-empty sequence of characters within a string.

 

Example 1:

Input: s = "aaaa"
Output: 2
Explanation: The longest special substring which occurs thrice is "aa": substrings "aaaa", "aaaa", and "aaaa".
It can be shown that the maximum length achievable is 2.

Example 2:

Input: s = "abcdef"
Output: -1
Explanation: There exists no special substring which occurs at least thrice. Hence return -1.

Example 3:

Input: s = "abcaba"
Output: 1
Explanation: The longest special substring which occurs thrice is "a": substrings "abcaba", "abcaba", and "abcaba".
It can be shown that the maximum length achievable is 1.

 

Constraints:

  • 3 <= s.length <= 50
  • s consists of only lowercase English letters.

代码结果

运行时间: 34 ms, 内存: 16.2 MB


/*
 题目思路:
 1. 使用Java Stream处理字符串子串和过滤特殊字符串。
 2. 统计每个特殊子串的出现次数并记录长度。
 3. 返回满足条件的最大长度,若不存在则返回-1。
 */
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Solution {
    public int longestSpecialSubstring(String s) {
        int n = s.length();
        return IntStream.rangeClosed(1, n)
                .boxed()
                .flatMap(len -> IntStream.rangeClosed(0, n - len)
                        .mapToObj(i -> s.substring(i, i + len)))
                .filter(this::isSpecial)
                .collect(Collectors.groupingBy(sub -> sub, Collectors.counting()))
                .entrySet().stream()
                .filter(entry -> entry.getValue() >= 3)
                .mapToInt(entry -> entry.getKey().length())
                .max().orElse(-1);
    }

    // 检查字符串是否为特殊字符串
    private boolean isSpecial(String s) {
        char firstChar = s.charAt(0);
        return s.chars().allMatch(c -> c == firstChar);
    }
}

解释

方法:

本题解采用哈希表记录每个字符的连续长度,从而确定是否存在符合条件的特殊子字符串。首先,初始化一个大小为26的哈希表(字典),对应于每个英文字母,用来存储该字符连续出现的长度。遍历字符串s,使用一个计数器来记录当前字符连续出现的次数。当遇到不同的字符时,将当前计数值存入相应字符的列表中,并重置计数器。遍历完成后,检查每个字符的列表,分析是否存在长度至少为3的子字符串。通过计算特定规则(如单个字符长度减2,最长两个字符长度比较等),更新可能的最长特殊子字符串长度。最后,如果没有找到符合条件的特殊子字符串,返回-1,否则返回记录的最大长度。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么在处理字符连续性时选择使用哈希表,并且为每个字母分别创建列表来存储其出现的长度?
使用哈希表和为每个字母分别创建列表的方法能够有效地跟踪和存储每个字符在字符串中出现的所有连续长度。这种数据结构允许我们在完成字符串的单次遍历后,能够快速访问任何字符的所有连续出现记录,从而便于后续分析这些长度是否满足题目的特殊条件。哈希表的键值对应于字母,值为该字母出现的所有连续长度的列表,使得数据的插入和查询操作都非常高效。
🦆
算法中对于最后一个字符的处理是在循环外进行的,这样的处理方式是否可能导致一些逻辑上的遗漏或错误?
算法在循环外处理最后一个字符是为了确保连续字符的计数被正确保存。在字符串遍历的最后,无论最后一个字符是否与前一个字符相同,其连续计数都需要被记录。如果不在循环外额外处理,那么字符串的最后一个连续字符序列将无法被记录,从而导致数据丢失。因此,这种处理方式是必要且正确的,能够确保所有字符连续性的完整记录。
🦆
在计算最长特殊子字符串长度时,为何选择长度减2或减1的策略?这种策略的合理性和准确性如何?
选择长度减2或减1的策略是为了确保找到的子字符串真正满足特殊性条件(即至少出现三次)。长度减2的情况考虑的是去掉一个字符后,剩余的子字符串是否仍有可能满足出现至少三次的条件。当一个字符连续出现的次数最少为3次时,去掉最前面和最后面的一个字符,中间的子字符串仍然可能满足条件。长度减1的策略则用于处理当第二长的连续长度足够接近最长长度时的情况。这些策略确保了算法在考虑减少字符的情况下仍能找到满足条件的最大长度,提高了方法的通用性和准确性。
🦆
题解中提到如果连续字符的长度列表中的最长三个长度相等,则可以直接使用这个长度,这种情况下为什么不需要减1或减2?
如果连续字符的长度列表中的最长三个长度相等,表明这个长度的子字符串至少出现了三次,且这三次出现是完全独立的。在这种情况下,即使考虑到可能的边界影响,三个相同的连续长度已经充分证明了这个长度的子字符串的重复性和稳定性,因此不需要进一步减少长度来满足至少出现三次的条件。直接使用这个长度能够确保不遗漏可能的最长特殊子字符串。

相关问题