Related
Given an array 'A' of size 'N' containing integers. You need to answer
'Q' queries of type [ L R X Y ]. In each of the query you need to
select at least 'X' elements and at most 'Y' elements from range 'L'
to 'R' of the array 'A' such that their sum is maximum.
Output the maximum sum achievable for each of the query.
Example :
N = 5
A = [ 1, 2, -1, -2, 3 ]
Q = [ [ 1, 3, 1, 2 ] , [ 3, 4, 1, 2 ] ]
Output : 3, -1
Expanation :
For query 1, we select integers 1 and 2 to get the sum 3. This is the
maximum sum achievable in the range index 1 to 3.
For query 2, we need to select at least 1 element so we select -1 to
get maximum sum -1.
Note :
The selected elements in the range L to R need not be consecutive. You can > select subsequence of integers to maximise the sum.
Constraints :
1<=N<=10^5
1<=Q<=10^5
-10^8 <= A[i] <= 10^8
1<=L<=R<=N
1<=X<=Y<=R-L+1
I tried to think of some approaches but could not find any algo for the above constraints. Any help/hint would be appreciated.
One approach is to preprocess the numbers by splitting into non-overlapping arrays of length L (for L equal to different powers of 2).
Sort each array, and compute the cumulative sum of each array.
Then for each query, identify the arrays which combine to make the query range and use bisection to identify the level T such that if taking all elements above T we end up with a legal number of elements and the highest sum.
There will be log(N) arrays involved, and log(N) steps in each bisection, so this should be reasonably fast.
(Note if our first evaluation shows that taking all positive elements ends up with too many, we need to find the lowest legal level by bisection, while if we end up with too few we need to find the highest legal level by bisection)
Example
Suppose we have an array A = [ 1, -1, 2, -2, 3, -3, 4, 0 ].
The preprocessing will split it into:
Two arrays of length 4: [ 1, -1, 2, -2], [ 3, -3, 4, 0 ]
Four arrays of length 2: [ 1, -1], [2, -2], [ 3, -3], [4, 0 ]
Eight arrays of length 1: [1], [-1], [2], [-2], [ 3], [-3], [4], [0 ]
Then with a query 3 to 5, we want the elements [-2,3,-3] which we can form from the arrays [-2] and [3,-3].
Suppose we now want to find the maximum sum from at least 2 elements.
We first try taking all positive elements, this only results in 1 element so we know we need to bisect for the highest legal level.
The bisection could work by trying some values, e.g.
All elements >= 0 gives 1 element, so value is too high
All elements >= -4 gives 3 elements, so value is too low
All elements >= -2 gives 2 elements, so value is just right
Say I have an array of N integers set to the value '0', and I want to pick a random element of that array that has the value '0' and put it to value '1'
How do I do this efficiently ?
I came up with 2 solutions but they look quite ineficient
First solution
int array[N] //init to 0s
int n //number of 1s we want to add to the array
int i = 0
while i < n
int a = random(0, N)
if array[a] == 0
array[a] = 1
i++
end if
end while
It would be extremely inefficient for large arrays because of the probability of collision
The second involves a list containing all the 0 positions remaining and we choose a random number between 0 and the number of 0 remaining to lookup the value in the list that correspond to the index in the array.
It's a lot more reliable than the first solution, since the number of operations is bounded, but still has a worst case scenario complexity of N² if we want to fill the array completely
Your second solution is actually a good start. I assume that it involves rebuilding the list of positions after every change, which makes it O(N²) if you want to fill the whole array. However, you don't need to rebuild the list every time. Since you want to fill the array anyway, you can just use a random order and choose the remaining positions accordingly.
As an example, take the following array (size 7 and not initially full of zeroes) : [0, 0, 1, 0, 1, 1, 0]
Once you have built the list of zeros positions, here [0, 1, 3, 6], just shuffle it to get a random ordering. Then fill in the array in the order given by the positions.
For example, if the shuffle gives [3, 1, 6, 0], then you can fill the array like so :
[0, 0, 1, 0, 1, 1, 0] <- initial configuration
[0, 0, 1, 1, 1, 1, 0] <- First, position 3
[0, 1, 1, 1, 1, 1, 0] <- Second, position 1
[0, 1, 1, 1, 1, 1, 1] <- etc.
[1, 1, 1, 1, 1, 1, 1]
If the array is initially filled with zeros, then it's even easier. Your initial list is the list of integers from 0 to N (size of the array). Shuffle it and apply the same process.
If you do not want to fill the whole array, you still need to build the whole list, but you can truncate it after shuffling it (which just means to stop filling the array after some point).
Of course, this solution requires that the array does not change between each step.
You can fill array with n ones and N-n zeros and make random shuffling.
Fisher-Yates shuffle has linear complexity:
for i from N−1 downto 1 do
j ← random integer such that 0 ≤ j ≤ i
exchange a[j] and a[i]
Given an array, the output array consecutive elements where total sum is 0.
Eg:
For input [2, 3, -3, 4, -4, 5, 6, -6, -5, 10],
Output is [3, -3, 4, -4, 5, 6, -6, -5]
I just can't find an optimal solution.
Clarification 1: For any element in the output subarray, there should a subset in the subarray which adds with the element to zero.
Eg: For -5, either one of subsets {[-2, -3], [-1, -4], [-5], ....} should be present in output subarray.
Clarification 2: Output subarray should be all consecutive elements.
Here is a python solution that runs in O(n³):
def conSumZero(input):
take = [False] * len(input)
for i in range(len(input)):
for j in range(i+1, len(input)):
if sum(input[i:j]) == 0:
for k in range(i, j):
take[k] = True;
return numpy.where(take, input)
EDIT: Now more efficient! (Not sure if it's quite O(n²); will update once I finish calculating the complexity.)
def conSumZero(input):
take = [False] * len(input)
cs = numpy.cumsum(input)
cs.insert(0,0)
for i in range(len(input)):
for j in range(i+1, len(input)):
if cs[j] - cs[i] == 0:
for k in range(i, j):
take[k] = True;
return numpy.where(take, input)
The difference here is that I precompute the partial sums of the sequence, and use them to calculate subsequence sums - since sum(a[i:j]) = sum(a[0:j]) - sum(a[0:i]) - rather than iterating each time.
Why not just hash the incremental sum totals and update their indexes as you traverse the array, the winner being the one with largest index range. O(n) time complexity (assuming average hash table complexity).
[2, 3, -3, 4, -4, 5, 6, -6, -5, 10]
sum 0 2 5 2 6 2 7 13 7 2 12
The winner is 2, indexed 1 to 8!
To also guarantee an exact counterpart contiguous-subarray for each number in the output array, I don't yet see a way around checking/hashing all the sum subsequences in the candidate subarrays, which would raise the time complexity to O(n^2).
Based on the example, I assumed that you wanted to find only the ones where 2 values together added up to 0, if you want to include ones that add up to 0 if you add more of them together (like 5 + -2 + -3), then you would need to clarify your parameters a bit more.
The implementation is different based on language, but here is a javascript example that shows the algorithm, which you can implement in any language:
var inputArray = [2, 3, -3, 4, -4, 5, 6, -6, -5, 10];
var ouputArray = [];
for (var i=0;i<inputArray.length;i++){
var num1 = inputArray[i];
for (var x=0;x<inputArray.length;x++){
var num2 = inputArray[x];
var sumVal = num1+num2;
if (sumVal == 0){
outputArray.push(num1);
outputArray.push(num2);
}
}
}
Is this the problem you are trying to solve?
Given a sequence , find maximizing such that
If so, here is the algorithm for solving it:
let $U$ be a set of contiguous integers
for each contiguous $S\in\Bbb Z^+_{\le n}$
for each $\T in \wp\left([i,j)\right)$
if $\sum_{n\in T}a_n = 0$
if $\left|S\right| < \left|U\left$
$S \to u$
return $U$
(Will update with full latex once I get the chance.)
I'm building a decision tree algorithm. The sorting is very expensive in this algorithm because for every split I need to sort each column. So at the beginning - even before tree construction I'm presorting variables - I'm creating a matrix so for each column in the matrix I save its ranking. Then when I want to sort the variable in some split I don't actually sort it but use the presorted ranking array. The problem is that I don't know how to do it in a space efficient manner.
A naive solution of this is below. This is only for 1 variabe (v) and 1 split (split_ind).
import numpy as np
v = np.array([60,70,50,10,20,0,90,80,30,40])
sortperm = v.argsort() #1 sortperm = array([5, 3, 4, 8, 9, 2, 0, 1, 7, 6])
rankperm = sortperm.argsort() #2 rankperm = array([6, 7, 5, 1, 2, 0, 9, 8, 3, 4])
split_ind = np.array([3,6,4,8,9]) # this is my split (random)
# split v and sortperm
v_split = v[split_ind] # v_split = array([10, 90, 20, 30, 40])
rankperm_split = rankperm[split_ind] # rankperm_split = array([1, 9, 2, 3, 4])
vsorted_dummy = np.ones(10)*-1 #3 allocate "empty" array[N]
vsorted_dummy[rankperm_split] = v_split
vsorted = vsorted_dummy[vsorted_dummy!=-1] # vsorted = array([ 10., 20., 30., 40., 90.])
Basically I have 2 questions:
Is double sorting necessary to create ranking array? (#1 and #2)
In the line #3 I'm allocating array[N]. This is very inefficent in terms of space because even if split size n << N I have to allocate whole array. The problem here is how to calculate rankperm_split. In the example original rankperm_split = [1,9,2,3,4] while it should be really [1,5,2,3,4]. This problem can be reformulated so that I want to create a "dense" integer array that has maximum gap of 1 and it keeps the ranking of the array intact.
UPDATE
I think that second point is the key here. This problem can be redefined as
A[N] - array of size N
B[N] - array of size N
I want to transform array A to array B so that:
Ranking of the elements stays the same (for each pair i,j if A[i] < A[j] then B[i] < B[j]
Array B has only elements from 1 to N where each element is unique.
A few examples of this transformation:
[3,4,5] => [1,2,3]
[30,40,50] => [1,2,3]
[30,50,40] => [1,3,2]
[3,4,50] => [1,2,3]
A naive implementation (with sorting) can be defined like this (in Python)
def remap(a):
a_ = sorted(a)
b = [a_.index(e)+1 for e in a]
return b
Let's say I have an array with 5 elements. How can I calculate all possible repetitive permutations of this array in C.
Edit: What I mean is creating all possible arrays by using that 5 number. So the positon matters.
Example:
array = [1,2,3,4,5]
[1,1,1,1,1]
[1,1,1,1,2]
[1,1,1,2,3]
.
.
A common way to generate combinations or permutations is to use recursion: enumerate each of the possibilities for the first element, and prepend those to each of the combinations or permutations for the same set reduced by one element. So, if we say that you're looking for the number of permutations of n things taken k at a time and we use the notation perms(n, k), you get:
perms(5,5) = {
[1, perms(5,4)]
[2, perms(5,4)]
[3, perms(5,4)]
[4, perms(5,4)]
[5, perms(5,4)]
}
Likewise, for perms(5,4) you get:
perms(5,4) = {
[1, perms(5,3)]
[2, perms(5,3)]
[3, perms(5,3)]
[4, perms(5,3)]
[5, perms(5,3)]
}
So part of perms(5,5) looks like:
[1, 1, perms(5,3)]
[1, 2, perms(5,3)]
[1, 3, perms(5,3)]
[1, 4, perms(5,3)]
[1, 5, perms(5,3)]
[2, 1, perms(5,3)]
[2, 2, perms(5,3)]
...
Defining perms(n, k) is easy. As for any recursive definition, you need two things: a base case and a recursion step. The base case is where k = 0: perms(n, 0) is an empty array, []. For the recursive step, you generate elements by prepending each of the possible values in your set to all of the elements of perms(n, k-1).
If I get your question correctly, you need to generate all 5 digit numbers with digits 1,2,3,4 and 5. So there is a simple solution - generate all numbers base five up to 44444 and then map the 0 to 1, 1 to 2 and so on. Add leading zeros where needed - so 10 becomes 00010 or [1,1,1,2,1].
NOTE: you don't actually have to generate the numbers themselves, you may just iterate the numbers up to 5**5(excluding) and for each of them find the corresponing sequence by getting it's digits base 5.
int increment(size_t *dst, size_t len, size_t base) {
if (len == 0) return 0;
if (dst[len-1] != base-1) {
++dst[len-1];
return 1;
} else {
dst[len-1] = 0;
return increment(dst, len-1, base);
}
}
Armed with this function you can iterate over all repetitive permutations of (0 ... 4) starting from {0, 0, 0, 0, 0}. The function will return 0 when it runs out of repetitive permutations.
Then for each repetitive permutation in turn, use the contents as indexes into your array so as to get a repetitive permutation of the array rather than of (0 ... 4).
In your given example, each position could be occupied by either 1, 2, 3, 4, 5. As there are 5 positions, the total number of possibilities = 5 * 5 * 5 * 5 * 5 = 5 ^ 5 = 3125. In general, it would be N ^ N. (where ^ is the exponentiation operator).
To generate these possibilities, in each of the positions, put the numbers 1, 2, 3, 4, 5, one by one, and increment starting from the last position, similar to a 5 digit counter.
Hence, start with 11111. Increment the last position to get 11112 ... until 11115.
Then wrap back to 1, and increment the next digit 11121 continue with 11122 ... 11125, etc. Repeat this till you reach the first position, and you would end at 55555.