I'm trying to solve pretty complex problem with combinatorics and counting subsets. First of all let's say we have given set A = {1, 2, 3, ... N} where N <= 10^(18). Now we want to count subsets that don't have consecutive numbers in their representation.
Example
Let's say N = 3, and A = {1,2,3}. There are 2^3 total subsets but we don't want to count the subsets (1,2), (2,3) and (1,2,3). So in total for this question we want to answer 5 because we want to count only the remaining 5 subsets. Those subsets are (Empty subset), (1), (2), (3), (1,3). Also we want to print the result modulo 10^9 + 7.
What I've done so far
I was thinking that this should be solved using dynamical programming with two states (are we taking the i-th element or not), but then I saw that N could go up to 10^18, so I was thinking that this should be solved using mathematical formula. Can you please give me some hints where should I start to get the formula.
Thanks in advance.
Take a look at How many subsets contain no consecutive elements? on the Mathematics Stack Exchange.
They come to the conclusion that the number of non-consecutive subsets in the set {1,2,3...n} is the fib(n+2) where fib is the function computing the Fibonacci sequence for the number n+2. Your solution to n=3 conforms to this solution. If you can implement the Fibonacci algorithm, then you can solve this problem, but solving the question for a number as large as 10^18 will still be a challenge.
As mentioned in the comments here, you can check out the fast doubling algorithm on Hacker Earth.
It will find Fibonacci numbers in O(log n).
Related
I read a question in an algorithm book:
"Given a positive integer n, choose 100 random permutations of [1,2,...,n],..."
I know how to generate random permutations with Knuth's algorithm. but does there exist any fast algorithms to generate large amount of permutations ?
Knuth shuffles require you to do n random swaps for a permutation of n elements (see http://en.wikipedia.org/wiki/Random_permutation#Knuth_shuffles) so the complexity is O(n) which is about the best you can expect if you receive a permutation on n elements.
Is this causing you a practical problem? If so, perhaps you could look at what you are doing with all those permutations in practice. Apart from simply getting by on less, you could think about deferring generating a permutation until you are sure you need it. If you need a permutation on n objects but only look at k of those n objects, perhaps you need a scheme for generating only those k elements. For small k, you could simply generate k random numbers in the range [0, n) at random, repeating generations which return numbers which have already come up. For small k, this would be unlikely.
There exist N! permutations of numbers from 1 to N. If you sort them lexicographically, like in a dictionary, it's possible to construct permutation knowing it order in a list of sorted permutations.
For example, let N=3, lexicographically sorted list of permutations is {123,132,213,231,312,321}. You generate number between 1 and 3!, for example 5. 5-th permutaion is 312. How to construct it?
Let's find the 1-st number of 5-th permutation. Let's divide permutations into blocks, criteria is 1-st number, I means such groups - {123,132},{213,231},{312,321}. Each group contains (n-1)! elements. The first number of permutation is the block number. 5-th permutation is in ceil(5/(3-1)!)=3 block. So, we've just found the first number of 5-th permutation it's 3.
Now I'm looking for not 5-th but (5-(n-1)!*(ceil(5/2)-1))=5-2*2=1-th permutation in
{3,1,2},{3,2,1}. 3 is determined and the same for all group members, so I'm actually searching for 1-th permutation in {1,2},{2,1} and N now is 2. Again, next_num = ceil(1/(new_N-1)!) = 1.
Continue it N times.
Hope you got the idea. Complexity is O(N) - because you constructing permutation elements one by one with arithmetical tricks.
UPDATE
When you got next number by arithmetical opearions you should also keep used array and instead of X take X-th unused Complexity becomes NlogN because logN needed for getting X-th unused element
I encountered the following interview question online, and came up with O(N^2) solution.
I want to know if there is a better way to solve this problem?
Problem: Which numbers in an unordered list can be represented as a sum of 3 other numbers in the list?
My O(N^2) solution:
Create a hashmap that stores sum of all 2 element pairs.
e.g. hashmap.insert(a[i] + a[j]), 0 <= i,j <= N-1
Once hashmap is built in step 1 (takes O(N^2) time,
I will pick a pair from nC2 pairs and see if this pair contains
the third element and the sum.
i.e. For all pairs of two elements(a[p], a[q]) where 0 <= p,q <= N-1
Find if hashmap contains (a[q] - a[p])
Cannot do better than O(N^2) because if you then you would have solved one of the most difficult problems in computer science that is to solve 3-sum problem in less than O(N^2). It is still an open question whether 3-sum can be solved less than O(N^2).
3-Sum
I am solving a problem from codeforces.
Our job is to find a minimum cost to make a given integer sequence be a non-decreasing sequence. We can increase/decrease any number of the sequence by 1 at each step and it will cost 1.
For example, when we are given a sequence 3, 2, -1, 2, 11, we can make the sequence be non decreasing with cost 4 (by decreasing 3 to 2 and increasing -1 to 2, so the non-decreasing sequence will be 2, 2, 2, 2, 11)
According the editorial of this problem, we can solve this problem using dynamic programming with 2 sequences, (one is the sequence we are given, and the other one is sorted sequence of the given one).
The outline of solution:
If we let a be the original sequence and b be the sorted sequence of the sequence a, and let f(i,j) be the minimal number of moves required to obtain the sequence in which the first i elements are non-decreasing and i-th element is at most bj. Then we can make recurrence as follows. (This is from the editorial of the problem)
f(1,1)=|a1-b1|
f(1,j)=min{|a1-bj|,f(1,j-1)}, j>1
f(i,1)=|ai-b1|+f(i-1,1), i>1
f(i,j)=min{f(i,j-1),f(i-1,j)+|ai-bj|}, i>1, j>1
I understand this recurrence. However, I can't figure out why we should compare the original sequence with the sorted one of itself and I am not sure whether we can get the correct minimum cost with another sequence other than the sorted sequence of the given one.
How we can prove the correctness of this solution? And how can we guarantee the answer with sorted sequence to be the minimum cost?
The point of the exercise is that this recurrence can be proven with induction. Once it is proven, then we have proven that f(n,n) is the minimum cost for winding up with a solution where the nth value is at most bn.
To finish proving the result there is one more step. Which is to prove that any solution where the nth value exceeds bn can be improved without increasing that maximum value. But that's trivial - just omit one of the +1s from the first value to exceed bn and you have a strictly better solution without a larger maximum. Therefore no solution winding up with a maximum greater than bn can be better than the best with a maximum at most bn.
Therefore we have the optimal solution.
I was reading this http://www.cas.mcmaster.ca/~terlaky/4-6TD3/slides/DP/DP.pdf and would like to know if there exists a solution with better time complexity to the partition problem.
From the link:
"Suppose a given arrangement S of non-negative numbers
{s1,...,sn} and an integer k. How to cut S into k or fewer ranges,
so as to minimize the maximum sum over all the ranges?"
e.g.
S = 1,2,3,4,5,6,7,8,9
k=3
By cutting S into these 3 ranges, the sum of the maximum range (8,9) is 17, which is the minimum possible.
1,2,3,4,5|6,7|8,9
The algorithm suggested in the link runs in O(kn^2) and uses O(kn) space. Are there more efficient algorithms?
Ok so apparently this was closed for being "off-topic"!?
But it's back up now so anyway, I found the solution to be binary searching the answer. Sorry I forgot one of the constraints was that the sum of all the integers would not exceed 2^64. So let C = cumulative sum of all integers. Then we can binary search for the answer using a
bool isPossible(int x)
function which returns true if it is possible to divide S into k partitions with maximum partition sum less than X. isPossible(int x) can be done in O(n) (by adding everything from left to right and if it exceeds x make a new partition). So the total running time is O(n*log(s)).
I came across this question and couldn't find a reasonable solution.
How would you divide an unsorted integer array into 2 equal sized sub-arrays such that, difference between sub-array sums is minimum.
For example: given an integer array a[N] (unsorted), we want to split the array into be split into a1 and a2 where a1.length == a2.length i.e N/2 and (sum of all numbers in a1 - sum of all numbers in a2) should be minimum.
For the sake of simplicity, let's assume all numbers are positve but there might be repetitions.
While others have mentioned that this is a case of the partition problem with modification, I'd like to point out, more specifically, that it is actually a special case of the minimum makespan problem with two machines. Namely, if you solve the two-machine makespan problem and obtain a value m, you obtain the minimum difference 2*m - sum(i : i in arr)
As the wikipedia article states, the problem is NP-complete for more than 2 machines. However, in your case, the List scheduling algorithm, which in general provides an
approximate answer, is optimal and polynomial-time for the two-machine and three-machine case given a sorted list in non-increasing order.
For details, and some more theoretical results on this algorithm, see here.