zoukankan      html  css  js  c++  java
  • 1177. Can Make Palindrome from Substring

    问题:

    给定一个字符串s,

    和一个字串操作数组queries

    [i, j, k]

    即对字符串s的i~j字符组成的子串,进行重新排列,且可从中最多(up to)选取k个字母,替换成任意字母,

    使得子串能够成为回文字符串。

    如果可以返回true,否则返回false。

    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.
    

      

    解法:

    回文字符串:

    特点:中间对称,前后两元素两两相同。

    由于本问题中,子字符串可以进行重新排序,因此对子字符串的顺序就不需要考虑了。

    只计算子字符串中,出现的字母个数,是否两两可相消。

    最后不能相互抵消的字母(假如有n个)中一半(n/2),替换成已存在的字母,形成新的相消对,即可成为回文字符串。

    最多需要n/2次字母替换,n/2<=k,则满足题意,可返回true。

    两两相消:

    这里我们想到了异或^运算:两两不同=1,两两相同=0

    使用bit位法,标记字母a~z:1<<(A[i]-'a')

    求字母出现的个数是否两两相消:

    求前缀字符串不能相消的字母标记:prefix ^= 1<<(A[i]-'a')

    i~j的子字符串:

    我们想到前缀求和的算法:substring(i,j)=presum(j)-presum(i-1)

    ps->presum的简写:

    ps(0)=0;
    ps(1)=sum(0,0);
    ps(2)=sum(0,1);
    ps(3)=sum(0,3);

    因此:sum(i,j)=ps(j+1)-ps(i)

    本题,在字母计数中,前缀求和即为:子字符串i~j,计算不能抵消的字母个数

    sum(i,j) = ps(j+1) ^ ps(i)

    抵消相同前缀。

    得到的sum(i,j)即为子字符串中出现奇数次(不能相消)的字母标记,

    要求有多少个这样的字母,即求这个标记中有多少个 1 即可。

    __builtin_popcount:该函数求参数变量中有多少个 1

    /2与k比较即可。

    代码参考:

     1 class Solution {
     2 public:
     3     vector<bool> canMakePaliQueries(string s, vector<vector<int>>& queries) {
     4         vector<bool> res;
     5         int prefix=0;
     6         vector<int> ps(1);
     7         //保存前缀字符串0~j=prefix
     8         //presum(0)=0, sum(i~j)=presum(j)-presum(i)
     9         for(char c:s){
    10             ps.push_back(prefix ^= 1<<(c-'a'));//去掉偶数个相同的字母
    11         }
    12         for(vector<int>q : queries){
    13             int odds = __builtin_popcount(ps[q[1]+1]^ps[q[0]]);
    14             //用异或^去掉:相同的部分前缀0~i-1
    15             //字符串sum(i~j)中,奇数个字母的个数
    16             res.push_back(odds/2<=q[2]);
    17         }
    18         return res;
    19     }
    20 };
  • 相关阅读:
    redis安装
    redis的使用场景和基本数据类型
    (传输层)tcp协议
    async/await
    Promise对象
    对称加密与非对称加密
    Js遍历数组总结
    HTTPS加密传输过程
    HTML节点操作
    Js的new运算符
  • 原文地址:https://www.cnblogs.com/habibah-chang/p/13113473.html
Copyright © 2011-2022 走看看