LeetCode-1177. Can Make Palindrome from Substring

Given a string s, we make queries on substrings of s.

For each query queries[i] = [left, right, k], we may rearrange the substring s[left], ..., s[right], and then choose up to k of them to replace with any lowercase English letter. 

If the substring is possible to be a palindrome string after the operations above, the result of the query is true. Otherwise, the result is false.

Return an array answer[], where answer[i] is the result of the i-th query queries[i].

Note that: Each letter is counted individually for replacement so if for example s[left..right] = "aaa", and k = 2, we can only replace two of the letters.  (Also, note that the initial string s is never modified by any query.)

 

Example :

Input: s = "abcda", queries = [[3,3,0],[1,2,0],[0,3,1],[0,3,2],[0,4,1]]
Output: [true,false,false,true,true]
Explanation:
queries[0] : substring = "d", is palidrome.
queries[1] : substring = "bc", is not palidrome.
queries[2] : substring = "abcd", is not palidrome after replacing only 1 character.
queries[3] : substring = "abcd", could be changed to "abba" which is palidrome. Also this can be changed to "baab" first rearrange it "bacd" then replace "cd" with "ab".
queries[4] : substring = "abcda", could be changed to "abcba" which is palidrome.

Constraints:

  • 1 <= s.length, queries.length <= 10^5
  • 0 <= queries[i][0] <= queries[i][1] < s.length
  • 0 <= queries[i][2] <= s.length
  • s only contains lowercase English letters.

题解:

没注意可以rearrange。。。

比如lunu, [0, 3, 1],可以把它变为luun,然后变为nuun就行。

记录前i个字符中所有字母出现次数,然后偶数可以配对,奇数需要改一下,最终总数为所有出现字母中奇数的数量除以2(两个不同只要改一次)。

class Solution {
public:
    vector<bool> canMakePaliQueries(string s, vector<vector<int>>& queries) {
        int n = queries.size();
        int l = s.length();
        vector<bool> res;
        vector<vector<int>> cnt(l + 1, vector<int>(26, 0));
        for (int i = 1; i <= l; i++) {
           cnt[i] = cnt[i - 1];
           cnt[i][s[i - 1] - 'a'] = cnt[i - 1][s[i - 1] - 'a'] + 1;
        }
        for (int i = 0; i < n; i++) {
            int dif = 0;
            for (int j = 0; j < 26; j++) {
                if ((cnt[queries[i][1] + 1][j] - cnt[queries[i][0]][j]) % 2 != 0){
                    dif++;
                }
            }
            dif /= 2;
            if (queries[i][2] >= dif) {
                res.push_back(true);
            }
            else {
                res.push_back(false);
            }
        }
        return res;
    }
};

讨论区一个强大的解法:

由于只有26个字母,并且只需记录他们出现的次数是奇数还是偶数,那么可以用位运算来优化。

算法思路同上,记录前i个字符中每个字母出现的次数是奇还是偶,每个字母出现就对其位置进行异或,则奇数次位为1,偶数次位为0,最后按位判断子串中每个字母出现次数是否为奇数。

class Solution {
public:
    vector<bool> canMakePaliQueries(string s, vector<vector<int>>& queries) {
        int n = queries.size();
        int l = s.length();
        vector<bool> res;
        vector<int> cnt(l + 1, 0);
        for (int i = 1; i <= l; i++) {
           cnt[i] = cnt[i - 1] ^ (1 << s[i - 1] - 'a');
        }
        for (int i = 0; i < n; i++) {
            int dif = 0;
            int x = cnt[queries[i][1] + 1] ^ cnt[queries[i][0]];
            while (x != 0) {
                if (x & 1 != 0) {
                    dif++;
                }
                x >>= 1;
            }
            dif /= 2;
            if (queries[i][2] >= dif) {
                res.push_back(true);
            }
            else {
                res.push_back(false);
            }
        }
        return res;
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值