前缀和+位运算,LeetCode 1542. 找出最长的超赞子字符串

一、题目

1、题目描述

给你一个字符串 s 。请返回 s 中最长的 超赞子字符串 的长度。

「超赞子字符串」需满足满足下述两个条件:

  • 该字符串是 s 的一个非空子字符串
  • 进行任意次数的字符交换后,该字符串可以变成一个回文字符串

2、接口描述

python3
class Solution:
    def longestAwesome(self, s: str) -> int:
cpp
class Solution {
public:
    int longestAwesome(string s) {
    }
};

3、原题链接

1542. 找出最长的超赞子字符串


二、解题报告

1、思路分析

这道题应该说一下子字符串是连续的。。。

我们考虑回文串的特点:至多有一个字符出现次数为奇数

那么对于超赞子串S[i,j]而言,一定满足最多只有一个字符出现次数为奇数

我们可以用10位二进制数字分别表示前缀[0, i]内字符0~9出现次数奇偶性

那么我们可以通过前缀和快速判断S[i,j]是否是超赞子串

而我们要的是最长长度

我们用prexor[i]代表到下标i为止字符出现次数奇偶性的前缀状态

我们发现如果S[i, j]满足每个字符都是偶次出现,那么prexor[i - 1] ^ prexor[j] = 0 => prexor[i - 1] = prexor[j]

如果S[i, j] 只有一个字符出现次数为奇数,那么prexor[i - 1] ^ prexor[j] 的 1 的个数为1

所以我们用哈希表pre统计每个前缀状态的最早出现下标,然后边遍历边维护前缀状态msk

对于每个msk,偶数超赞子串我们其最大长度为i - pre[msk]

奇数超赞子串,其最大长度为 i - pre[msk ^ (1 << k)]

pre哈希表初始都为n,然后pre[0] = -1

2、复杂度

时间复杂度: O(nU),U为字符个数 空间复杂度:O(1 << U)

3、代码详解

python3
class Solution:
    def longestAwesome(self, s: str) -> int:
        n = len(s)
        pre = [n] * (1 << 10)
        msk = ret = 0
        pre[0] = -1
        for i, x in enumerate(map(int, s)):
            msk ^= (1 << x)
            ret = max(ret, i - pre[msk], max(i - pre[msk ^ (1 << b)] for b in range(10)))
            if pre[msk] == n:
                pre[msk] = i
        return ret
cpp
class Solution {
public:
    int longestAwesome(string s) {
        int n = s.size(), msk = 0, ret = 0;
        vector<int> pre(1 << 10, n);
        pre[0] = -1;
        for (int i = 0; i < n; i ++) {
            msk ^= 1 << (s[i] ^ 48);
            ret = max(ret, i - pre[msk]);
            for (int j = 0; j < 10; j ++) ret = max(ret, i - pre[msk ^ 1 << j]);
            if (pre[msk] == n) pre[msk] = i;
        }
        return ret;
    }
};

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EQUINOX1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值