LeetCode连接两字母单词得到的最长回文串

方法一:贪心 + 哈希表
思路与算法

根据回文串的定义,回文串可以由奇数或者偶数个 words 中的单词拼接而成,但必须满足以下条件:

如果数量为奇数,那么位于正中间的单词必须是回文字符串(即两个字符相等);

每个单词和反转后对应位置的单词必须互为反转字符串。

根据上面的两个条件,我们可以得出构造最长回文串的规则:

对于两个字符不同的单词,需要尽可能多的成对选择它和它的反转字符串(如有);

对于两个字符相同的单词,需要尽可能多的成对选择该单词;

如果按照上述条件挑选后,仍然存在未被选择的两个字符相同的单词(此时该字符串只可能有一个未被选择,且该字符串一定在 words 中出现奇数次),我们可以任意选择一个。

因此,我们用哈希表统计 words 中每个单词的出现次数。随后,我们遍历哈希表的所有元素,并用 res 维护可能构成回文字符串的最长长度,同时用初值为 false 的布尔变量 mid 判断是否存在可以作为中心单词的、出现奇数次的回文单词。在遍历到字符串 word 时,我们首先求出它反转后的字符串 rev,此时根据 word 与 rev 的关系,有以下两种情况:

word

=rev,此时我们需要统计两者在 words 出现次数的最小值,即为成对选择的最多数目。假设此时对数为 n,则其对最长回文字符串贡献的字符长度为 4n,我们将 res 加上对应值;

word=rev,此时可以构成的对数为 ⌊m/2⌋,即对最长回文字符串贡献的字符长度为 4⌊m/2⌋,我们同样将 res 加上对应值。除此以外,我们还需要判断 word 的出现次数 m 是否为奇数:

如果 m 为奇数,则存在可以作为中心单词的剩余回文单词,我们将 mid 置为 true;

如果 m 为偶数,则不存在可以作为中心单词的剩余回文单词,我们不改变 mid 的取值。

最后,我们根据 mid 的取值,判断最长回文串是否含有中心单词。如果 mid 为 true,则代表含有,我们将 res 加上 2;反之则没有,我们不进行任何操作。

最后,我们返回 res 作为最长回文串的长度。

细节

在遍历哈希表中的每个单词时,为了避免重复计算成对选择的单词,我们只在 word 的字典序大于等于 rev 时更新 res。

func longestPalindrome(words []string) int {
    freq := make(map[string]int)
    for _, word := range words {
        freq[word]++
    }
    res := 0
    mid := false
    for word, cnt := range freq {
        rev := string(word[1]) + string(word[0])
        if word == rev {
            if cnt%2 == 1 {
                mid = true
            }
            res += 2 * (cnt / 2 * 2)
        } else if strings.Compare(word, rev) > 0 {
            res += 4 * min(freq[word], freq[rev])
        }
    }
    if mid {
        res += 2
    }
    return res
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值