number of substring which are whose anagrams are palindrome

那年仲夏 提交于 2021-02-08 10:47:34

问题


Given a string of digits, count the number of subwords (consistent subsequences) that are anagrams of any palindrome.

My attempt in Python:

def ispalin(s):
    if len(s)%2==0:
        for i in s:
            if s.count(i)%2!=0:
                return False
    else:
        sum =0
        for i in set(s):
            if s.count(i)%2==1:
                sum = sum+1
        if sum == 1:
            return True
        else:
            return False

    return True

def solution(S):
    # write your code in Python 3.6
    count=len(S)
    for i in range(len(S)):
        for j in range(i+1,len(S)):
            if ispalin(S[i:j+1]):
                count=count+1

    return count

i/o format

For example, given:

    S = "02002"
the function should return 11. 
these are 11 substrings whose anagrams are palindrome
"0", "2", "0", "0", "2", "00", "020", "200", "002", "2002", "02002"

It is giving time limit exceeded for big strings. How can I optimize the above code?

i bet there exists a better solution than this here is the proof [image][1]

https://i.stack.imgur.com/7x3Jq.png


回答1:


There is an O(n) solution for this problem. The first thing to notice is, a substring is anagram of any palindrome if number of its including digits be even or at most one odd exist. e.g. "20020" is anagram of plaindrome because number of '2's is even and number of '0's is odd(at most one odd) while "200202" is not ok.

So the only thing we need to keep is parity of number of digits not sum of them. we can use a 10-bit number to show the parities of all digits. Starting from 0 each time we visit a digit in string, we can xor the parity number with (2^digit). following your example for "02002" here is the parity numbers generated by iterating through the string in binary format:

parity_array = {0000000000, 0000000001, 0000000101, 0000000100, 0000000101 0000000001}

Now we need to count the number of anagrams in linear time. Iterating over the parity_array we use another array of size 1024 (let's call it memo) to keep the number of times we visit a specific number in parity_array. As I mentioned before the substring is ok if and only if the number of 1 bits in their binary parity representation be at most 1. So for each member of parity_array we need to check and add 11 elements in memo having xor with current parity_array value equal to: {0 or 1 or 2 or 4 or 8 ... or 1024} and sum up the results. The total complexity is O(n).

Edit: I added C++ code for what I explained above. I can also add python code, if you want:

string sample = "02002";
int parity = 0;
vector<int> parity_array;
parity_array.push_back(parity);
for(int i=0; i<sample.size(); ++i){
    parity ^= 1<<(sample[i]-'0');
    parity_array.push_back(parity);
}
int memo[1025] = {0};
int res=0;
for(int i=0;i<parity_array.size();++i){
    for(int j=-1;j<10;++j)
        res += memo[(1<<j)^parity_array[i]];
    memo[parity_array[i]]++;
}
cout<<res<<endl;



回答2:


You can get quadratic complexity using O(n) of memory.

Make array[0..9] of digit counters (or use another data structure convenient for Python)

Walk through the string, increment counter for current digit and add modified array to the list. After that list will contain "cumulative sums" - counts for every digit upto every index (for example, five 2's before 40-th string entry)

Now to get count for digit between i-th and j-th entries, just subtract C[j][digit] - C[i][digit]

Interesting question - does better complexity solution exist?



来源:https://stackoverflow.com/questions/47629449/number-of-substring-which-are-whose-anagrams-are-palindrome

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!