Let L be a language s.t. for every natural n, the number of words of length n in L is n.
The alphabet is {0,1}.
And let's assume that L is NP. Why L-complement is also in NP?
Since L is in NP it is decidable (recursive) and so is its complement L'. Now, L' may or may not be in NP. But we are given that for any string length n, exactly one string belong to L, which means for any string length all but one string belong to L'.
Now, definition of NP says that all "yes" instances of the problem can be solved in polynomial time using a nondeterministic TM. So, given an instance of , we non-deterministically take all words of length n, where n is the length of w, and see if it is in L. As soon as we get the word (such a word is sure to exist as exactly one word of length n belong to L), we see if this word is same as x. If it is not same (and only if it is not same), x in L' and we get this answer in polynomial time making L' an NP problem.
If it is known a-priori that L has the property that there are exactly n words of length n in L, then your statement follows. In fact, this works for any polynomial amount of words in L. In other words, if we allow there to be poly(n) words in L with poly(n) known a-priori, the idea still works. To see this, note that to find all words of length n is L is also in NP since there is a polynomial number of them.
To see if s in {0,1}* is in L-complement, just form the certificate for all words of length |s|, and see if s is one of the words. If s is one of the words, then of course, s is in L, and if s is not one of the words, s is in L-complement.
Related
Task here is to find palindromes formed by combining pairs of the original word list (so for below, stuff like "callac" and "laccal"). I thought I had an idea of pre-computing all the reversed versions of each word (N). Then for each original word, compare with each reversed word... but then we're back to N*N.
Maybe we could sort the list. And then for each word we're working on, do a binary search for words whose first character matches our word's first or last character and check from there resulting in some kind of N log N situation?
My code:
data = ["cal", "lac", "mic", "blah", "totally", "ylla", "rum", "mur", "listen", "netsil"]
def get_palindrome_pairs(words):
palindromes = []
for i in range(len(words)):
for j in range(i+1, len(words)):
combined = words[i] + words[j]
combined_swapped = words[j] + words[i]
if combined == combined[::-1]:
palindromes.append(combined)
if combined_swapped == combined_swapped[::-1]:
palindromes.append(combined_swapped)
return palindromes
print(get_palindrome_pairs(data))
Edit: my original algorithm did not work. The situation is, in fact, more complicated than this because you might have a ["abc", "ba"] situation where the combination gives you "abcba", which is a palindrome. You need to use a more sophisticated approach to account for this.
First, note that one can use a modified KMP algorithm to find, for any strings s1 and s2, all prefixes of (or, to be more precise, the lengths of all prefixes of) s1 which are suffixes of s2. This can be done in linear time. The basic version of KMP can be easily modified to find the longest prefix of s1 which is a suffix of s2; one can then use the backtracking table to find all the others.
Second, note that we can use this to find all palindromic prefixes of a string s in linear time. This is because a palindromic prefix of s is precisely a prefix of s which is a suffix of reversed(s).
Now suppose we have strings s and k, and length(s) >= length(k). Then ks is a palindrome iff we can write s = z reversed(k), where z is a palindrome.
To determine whether we have any s, k such that length(s) >= length(k) and ks is a palindrome, store all strings in a trie. Then, for each string s, find all its palindromic prefixes. Walk through s backwards to find all k in the trie such that reversed(k) is a suffix of s. If there is any such k, check to see if the corresponding prefix is a palindrome. If so, we have found k and s such that ks is a palindrome.
To determine whether we have any s, k such that length(s) >= length(k) and sk is a palindrome, it suffices to repeat the above step, but first reversing all the strings.
The total runtime will be O(k + n) where k is the total number of characters across all strings and n is the number of strings.
I came across the following algorithms problem(src: http://www.careercup.com/question?id=15029889)
Problem:
c = ‘a’
w = “apple”
c covers w, iff w contains c.
c_set = {‘a’, ‘b’, ‘c’, ‘g’}
w_set = {‘apple’, ‘ibm’, ‘cisco’, ‘google’}
c_set covers w_set, iff every w in w_set is covered by some c in c_set.
Given c_set and w_set, Whether w_set is covered by c_set?
Follow up: if w_set is fixed say a book, how to determine whether a c_set covers this w_set?
One possible solution is:
If we use 26bits(1 bit for each character) to represent each word in w_set,
and then also form a similar bitmask for c_set, a solution to check coverage
would be to do "c_set_bitmask & word_i_bitmask". If this is non-zero for each
word, then we have covered every word.
My question is, can we do anything better than this, given that
the w_set is static e.g. a book.
One possible solution is of O(nlogk) ~ O(n) where n = total number of 'letters' in w_set and k = number of letters in c_set. max(k) = 26. Hence we can assume k is constant.
The algorithm seems naïve but I can't see any solution better than O(n) because in any algorithm you will atleast need to scan all the letters in w_set to check whether they are present in c_set.
Sort c_set lexicographically. (O(klogk)) ~ constant
Scan each word in w and perform binary search for the letters in c_set. (O(nlogk)) ~ O(n).
My professor gave us the following explanation for the recursive algorithm for finding the permutations of a set of numbers:
When he has (T(m+1), n-1)) where does that come from? Why is it m+1 and n-1? I'm really confused as to where that comes from.
As he said, m represents the current size of P and n represents the size of S, in each recursive call you remove a number from S and add it to P, thus the size of your current permutation is increased by 1 (m+1) and the number of available numbers to add to the permutation is decreased by 1 (n-1)
Note that it is multiplied by n as you perform this action for each number in S.
Note that part that says:
Let m be the length of P and n be the size of S
And then in printperm(P, S), you're calling printperm((P,i), S-{i}).
So, when recursing, we will add one element to P, and remove on element from S.
Thus m will increase by one and n will decrease by one, thus we get T(m+1, n-1)
I hope that helps.
I have to implement an algorithm that solves the multi-selection problem.
The multiselection problem is:
Given a set S of n elements drawn from a linearly ordered set, and a set K = {k1, k2,...,kr} of positive integers between 1 and n, the multiselection problem is to select the ki-th smallest element for all values of i, 1 <= i <= r
I need to solve the average case on Θ(n log r)
I've found a paper that implements the solution I need, but it assumes that there are no repeated numbers on the set S. The problem is that I can't assume that and I don't know how to adapt the algorithm of that paper to support repeated numbers.
The paper is here: http://www.ccse.kfupm.edu.sa/~suwaiyel/publications/multiselection_parCom.pdf
and the algorithm is on the second page. Any tips are welcome!
For posterity: the algorithm to which Ivan refers is to sort K, then solve the problem recursively as follows. Use QuickSelect to find the ki-th smallest element x where i is ceil(r/2), then recurse on the smaller halves of K and S, and the larger halves of K and S, splitting K about i and S about x.
Finding algorithms that work in the presence of degeneracy (here, equal elements) is often not a high priority for authors of theoretical works, because it makes the presentation of the common case more difficult and doesn't often play a role in determining the computational complexity of the problem. This is essentially a one-dimensional problem, and the black box solution is easy; replace the i-th element of the input yi by (yi, i) and break ties in the comparisons using the second component.
In practice, we can do better. Instead of recursing on {y : y in S, y < x} and {y : y in S, y > x}, use a three-way partitioning algorithm about x (see, e.g., every sufficiently complete treatment of QuickSort), then divide the array S by index instead of value.
I am given N numbers, n1, n2, n3, n4, …, nN (all being positive). Finally I am given a number K as input.
I am asked if it is possible to find some possible combination over n1, n2, …, nN such that the sum equals K, i.e. find coefficients a, b, c, …, n such that:
a·n1 + b·n2 + … + n·nN = K
where a, b, c, …, n may assume any integral value from 0 to K.
We just need to find out whether such a combination exist.
What I have been thinking is placing limits over the extreme values of a, b, …, n. For example, a can be bounded as: 0 ≤ a ≤ floor(K/a). Similarly, defining ranges for b, c, …, n. However, this algorithm eventually turns out to be O(nn-1) in the worst case.
Is this problem similar to Bin Packing problem? Is it NP complete?
Please help me with a better algorithm (I am not even sure if my algorithm is correct!!).
This is just another variant of the Knapsack problem (see the unbounded knapsack section) and is just as NP-complete and hard as the other versions.
Of course, if K is small you can use the dynamic programming solution and if N is small exaustive search works well also.
This solution supposes that the numbers n1, n2, ... nN are integers (or that they have a "smallest common divisor")
I've got a O(K*N) algorithm (thanks to missingno for the correction). The idea is a bit of dynamic programming, a bit of the Sieve of Eratosthenes.
Begin by creating a list L of K+1 booleans. L[i] is true if you can "build" the number i (more on that later). All values of L are initialised as false, except L[0]==true
Begin with you first number n1. For every value of i between 1 and K, check if L[i-n1]==true. Of course, if i-n1<0, then do as if L[i-n1]==false. If L[i-n1]==true, then change L[i] to true. Now, you have L[n1]==true, L[2*n1]==true, L[3*n1]==true ...
What does L mean now? L represent the numbers in [0..K] that can be built with only n1. If L[K]==true, congratulations, there is a solution built with only n1!
Take the number n2, and do the same. For every value of i between 1 and K such that L[i]==false, check if L[i-n2]==true. If it's the case change L[i] to true.
What does L mean now? L represent the numbers in [0..K] that can be built with n1 and n2. If L[K]==true, congratulations, there is a solution built with only n1 and n2!
If after filling L with all you N values L[K]==false, there is no solution to your problem.
The problem with dynamic programming is that it's always a problem to retrieve the solution once you've proven that there exists one... You need another list S such that S[i] describes what are the coefficients needed to "build" i. (exists only if L[i]==true of course)
This is an integer program, so if you have access to a solver, I'd recommend you profile its performance and see if it works for you.