力扣字符串练习题(无重复字符的最长子串、最长回文子串)

75 阅读3分钟

无重复字符的最长子串

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

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: s = "abcabcbb"

输出: 3 

解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

示例 2:

输入: s = "bbbbb"

输出: 1

解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

示例 3:

输入: s = "pwwkew"

输出: 3

解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。

请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

提示:

  • 0 <= s.length <= 5 * 104 = s 由英文字母、数字、符号和空格组成

代码

class Solution {
    public int lengthOfLongestSubstring(String s) {
        int n = s.length();
        int maxLength = 0;
        int start = 0;
        Map<Character, Integer> charMap = new HashMap<>();
        
        for (int end = 0; end < n; end++) {
            char c = s.charAt(end);
            if (charMap.containsKey(c)) {
                start = Math.max(start, charMap.get(c) + 1);
            }
            charMap.put(c, end);
            maxLength = Math.max(maxLength, end - start + 1);
        }
        
        return maxLength;
    }
}

思路分析

  1. 定义一个窗口的起始位置start、最大长度maxLength,以及一个哈希表charMap用于记录字符的索引。
  2. 遍历字符串s的每个字符,使用双指针来构建滑动窗口。
  3. 如果当前字符c在哈希表charMap中存在,并且其索引大于等于窗口的起始位置start,则更新start为该字符的索引加1,即将窗口的起始位置右移。
  4. 将当前字符c及其索引存入哈希表charMap中。
  5. 计算当前窗口的长度,即end - start + 1,并更新maxLength为最大长度。
  6. 重复步骤2至步骤5,直到遍历完整个字符串。
  7. 返回最大长度maxLength

最长回文子串

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

给你一个字符串 s,找到 s 中最长的回文子串。

如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。

示例 1:

输入:s = "babad"

输出:"bab"

解释:"aba" 同样是符合题意的答案。

示例 2:

输入:s = "cbbd"

输出:"bb"

提示:

  • 1 <= s.length <= 1000
  • s 仅由数字和英文字母组成

代码

class Solution {
    public String longestPalindrome(String s) {
        int n = s.length();
        boolean[][] dp = new boolean[n][n];
        int maxLength = 0;
        int start = 0;
        
        // 初始化单个字符和相邻两个字符的回文串
        for (int i = 0; i < n; i++) {
            dp[i][i] = true;
            if (i < n - 1 && s.charAt(i) == s.charAt(i + 1)) {
                dp[i][i + 1] = true;
                start = i;
                maxLength = 2;
            }
        }
        
        // 从长度为3的回文串开始判断
        for (int len = 3; len <= n; len++) {
            for (int i = 0; i <= n - len; i++) {
                int j = i + len - 1;
                if (s.charAt(i) == s.charAt(j) && dp[i + 1][j - 1]) {
                    dp[i][j] = true;
                    start = i;
                    maxLength = len;
                }
            }
        }
        
        return s.substring(start, start + maxLength);
    }
}

思路分析

  1. 定义一个二维布尔数组dp,其中dp[i][j]表示字符串从索引i到索引j的子串是否为回文串。
  2. 初始化单个字符和相邻两个字符的回文串,即dp[i][i] = truedp[i][i+1] = true,并记录最长回文串的起始位置start和长度maxLength
  3. 从长度为3的回文串开始判断。外层循环控制回文串的长度,内层循环遍历字符串,判断子串是否为回文串。
  4. 如果子串的两端字符相等,并且子串去掉两端字符后仍为回文串,则当前子串也为回文串,将dp[i][j]设为true,并更新最长回文串的起始位置start和长度maxLength
  5. 重复步骤3和步骤4,直到遍历完整个字符串。
  6. 返回最长回文子串,即根据起始位置start和长度maxLength从原字符串中截取。