跳转至

409. 最长回文串

题目描述

给定一个包含大写字母和小写字母的字符串 s ,返回 通过这些字母构造成的 最长的 回文串 的长度。

在构造过程中,请注意 区分大小写 。比如 "Aa" 不能当做一个回文字符串。

 

示例 1:

输入:s = "abccccdd"
输出:7
解释:
我们可以构造的最长的回文串是"dccaccd", 它的长度是 7。

示例 2:

输入:s = "a"
输出:1
解释:可以构造的最长回文串是"a",它的长度是 1。

 

提示:

  • 1 <= s.length <= 2000
  • s 只由小写 和/或 大写英文字母组成

解法

方法一:计数

一个合法的回文字符串,最多存在一个出现奇数次数的字符,其余字符出现次数均为偶数。

因此,我们可以先遍历字符串 \(s\),统计每个字符出现的次数,记录在数组或哈希表 \(cnt\) 中。

然后,我们遍历 \(cnt\),对于每个次数 \(v\),将 \(v\) 除以 2 取整,再乘以 2,累加到答案 \(ans\) 中。

最后,如果答案小于字符串 \(s\) 的长度,则将答案加一,返回 \(ans\)

时间复杂度 \(O(n + |\Sigma|)\),空间复杂度 \(O(|\Sigma|)\)。其中,\(n\) 为字符串 \(s\) 的长度,而 \(|\Sigma|\) 为字符集大小,在本题中 \(|\Sigma| = 128\)

1
2
3
4
5
6
class Solution:
    def longestPalindrome(self, s: str) -> int:
        cnt = Counter(s)
        ans = sum(v // 2 * 2 for v in cnt.values())
        ans += int(ans < len(s))
        return ans
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Solution {
    public int longestPalindrome(String s) {
        int[] cnt = new int[128];
        int n = s.length();
        for (int i = 0; i < n; ++i) {
            ++cnt[s.charAt(i)];
        }
        int ans = 0;
        for (int v : cnt) {
            ans += v / 2 * 2;
        }
        ans += ans < n ? 1 : 0;
        return ans;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Solution {
public:
    int longestPalindrome(string s) {
        int cnt[128]{};
        for (char c : s) {
            ++cnt[c];
        }
        int ans = 0;
        for (int v : cnt) {
            ans += v / 2 * 2;
        }
        ans += ans < s.size();
        return ans;
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
func longestPalindrome(s string) (ans int) {
    cnt := [128]int{}
    for _, c := range s {
        cnt[c]++
    }
    for _, v := range cnt {
        ans += v / 2 * 2
    }
    if ans < len(s) {
        ans++
    }
    return
}
1
2
3
4
5
6
7
8
9
function longestPalindrome(s: string): number {
    const cnt: Record<string, number> = {};
    for (const c of s) {
        cnt[c] = (cnt[c] || 0) + 1;
    }
    let ans = Object.values(cnt).reduce((acc, v) => acc + Math.floor(v / 2) * 2, 0);
    ans += ans < s.length ? 1 : 0;
    return ans;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
use std::collections::HashMap;

impl Solution {
    pub fn longest_palindrome(s: String) -> i32 {
        let mut cnt = HashMap::new();
        for ch in s.chars() {
            *cnt.entry(ch).or_insert(0) += 1;
        }

        let mut ans = 0;
        for &v in cnt.values() {
            ans += (v / 2) * 2;
        }

        if ans < (s.len() as i32) {
            ans += 1;
        }

        ans
    }
}

方法二:位运算 + 计数

我们可以使用一个数组或哈希表 \(odd\) 记录字符串 \(s\) 中每个字符是否出现奇数次,用一个整型变量 \(cnt\) 记录出现奇数次的字符个数。

遍历字符串 \(s\),对于每个字符 \(c\),将 \(odd[c]\) 取反,即 \(0 \rightarrow 1\), \(1 \rightarrow 0\)。如果 \(odd[c]\)\(0\) 变为 \(1\),则 \(cnt\) 加一;如果 \(odd[c]\)\(1\) 变为 \(0\),则 \(cnt\) 减一。

最后,如果 \(cnt\) 大于 \(0\),答案为 \(n - cnt + 1\),否则答案为 \(n\)

时间复杂度 \(O(n)\),空间复杂度 \(O(|\Sigma|)\)。其中,\(n\) 为字符串 \(s\) 的长度,而 \(|\Sigma|\) 为字符集大小,在本题中 \(|\Sigma| = 128\)

1
2
3
4
5
6
7
8
class Solution:
    def longestPalindrome(self, s: str) -> int:
        odd = defaultdict(int)
        cnt = 0
        for c in s:
            odd[c] ^= 1
            cnt += 1 if odd[c] else -1
        return len(s) - cnt + 1 if cnt else len(s)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Solution {
    public int longestPalindrome(String s) {
        int[] odd = new int[128];
        int n = s.length();
        int cnt = 0;
        for (int i = 0; i < n; ++i) {
            odd[s.charAt(i)] ^= 1;
            cnt += odd[s.charAt(i)] == 1 ? 1 : -1;
        }
        return cnt > 0 ? n - cnt + 1 : n;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Solution {
public:
    int longestPalindrome(string s) {
        int odd[128]{};
        int n = s.length();
        int cnt = 0;
        for (char& c : s) {
            odd[c] ^= 1;
            cnt += odd[c] ? 1 : -1;
        }
        return cnt ? n - cnt + 1 : n;
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
func longestPalindrome(s string) (ans int) {
    odd := [128]int{}
    cnt := 0
    for _, c := range s {
        odd[c] ^= 1
        cnt += odd[c]
        if odd[c] == 0 {
            cnt--
        }
    }
    if cnt > 0 {
        return len(s) - cnt + 1
    }
    return len(s)
}
1
2
3
4
5
6
7
8
9
function longestPalindrome(s: string): number {
    const odd: Record<string, number> = {};
    let cnt = 0;
    for (const c of s) {
        odd[c] ^= 1;
        cnt += odd[c] ? 1 : -1;
    }
    return cnt ? s.length - cnt + 1 : s.length;
}

评论

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy