力扣日记1177

1. 前言

最近看见周围同学不少已经有了好去处,顿感菜菜,写写力扣复习下408吧那就。

2. 题目

LeetCode 1177 构建回文串检测

2.1 题意

对字符串s做多次查询,每次查询:字符串下标[i,j]之间,最多替换 k 个字符成,且可调整顺序,最后是否可以变成回文串。

2.2 分析

时间复杂度在O(n)

1 <= s.length, queries.length <= 10^5

可以想到肯定遍历一遍字符串将信息存起来,每次查询直接使用。

  • 怎么查询
    • 关键是怎么查询,关系到怎么存信息
    • 使用记录的下标i,j的信息
    • 统计已经出现落单的字符个数, 成对的可以放在两边凑回文串,如果查询长度为奇数还可以将一个落单的字符放在字符串中间
    • 落单的个数 - 查询长度是否为奇数 <= 可变化的字符数 * 2 满足为true
    • 为什么不等式右边乘2,因为字符变一半就可以和另一半相同
  • 怎么存信息?
    • 题中只有小写字母,可以直接用数组存,mp[i]记录字符串到下标i的信息,具体可以开一个大小26的数组mp[i][0],表示字符串到下标i时字符a出现的次数

2.3 我的解法

class Solution {
public:
    vector<bool> canMakePaliQueries(string s, vector<vector<int>>& queries) {
        int n = s.length();
        int m = queries.size();
        vector<vector<int> > mp(n+1, vector(26, 0));
        // 遍历获取信息
        // 注意细节:下标
        // vector多开1方便下面查询 避免越界
        // mp[i] 对应得信息实际上是到下标i-1的信息
        for(int i=1; i<=n; i++){
            for(int j=0; j<26;j++){
                mp[i][j] = mp[i-1][j];
            }
            mp[i][s[i-1]-'a']++;
        }

        // 查询获得结果
        vector<bool> ans;
        for(int i=0; i<m; i++){
            // 是否奇数长度
            int oddFlag = (queries[i][1] - queries[i][0] + 1)%2;
            // 落单个数
            int oddNum = 0;
            for(int j=0; j<26; j++){
                // 细节,下标
                // 是queries[i][1]+1 和 queries[i][0]
                // 因为queries[i][1]+1记录的是到下标queries[i][1]的信息,需要用到
                // queries[i][0]记录的是到下标queries[i][0]-1的信息
                // 两者相减才能包括到左边端点的信息
                oddNum += ( (mp[queries[i][1]+1][j] - mp[queries[i][0]][j])%2 );
            }
            ans.emplace_back(bool(oddNum-oddFlag <= 2*(queries[i][2] ) ) );
        }
        return ans;
    }
};

2.4 学习题解反思

我的时间复杂度O(26n), 空间复杂度O(26n) (即为O(n))

题解中对存的信息进行了压缩,并且使用异或计算很巧妙。

统计落单的个数,实际就是字符串中字符数目为奇数的字符个数,实际只用看奇偶,不用记录个数,只需要用1位01记录1个字符,比如0表示字符有偶数个,1表示奇数个;又共26个字符,使用26位用one-hot编码记录,也就是每个下标只需要一个int就可以记录信息。
另外统计信息时使用异或运算, count[i + 1] = count[i] ^ (1 << (s[i] - ‘a’)); 因为当前下标较于前一个下标只多一个变化,只需要将变化的位改变,(1 << (s[i] - ‘a’))中,要改变的位为1,1异或等于取反符合奇变偶、偶变奇; 而其他位置异或的数为0,不变。

虽然题解的时间空间复杂度渐进意义下和我的解法是相同,但是实际上性能是比我的写法好的。

题解的查询方法也很有特色: count[r + 1] ^ count[l]然后统计1的个数
可以这么做是因为这样如果两个位置都是1或是0,那么这段字符串中肯定是偶数个该字符,反之奇数个字符,和异或相同。
(实际这里的统计1的个数也给时间复杂度加上了一个常数26)

2.5 bug日记

2.5.1 不等式推导错误

落单的个数 - 查询长度是否为奇数 <= 可变化的字符数 * 2 满足为true不等式推导错
(右边没有乘2

3. 后记

仅分享自己的想法,有意见和指点非常感谢

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值