Find the k-th sum from sums of every pair - algorithm

I'm given the array with n elements and I need to find k-th sum from sums of every pair n^2 in time complexity O(n*logn), sums are in ascending order.
Example input
In the first line are given number of elements and number of sum to find. In the second line list of number which sums of pair we need to generate.
3 6
1 4 6
The answer is 8 for given list, below is array of every pair of sums, where 8, sum of 4+4 is on the 6-th position.
2 5 5 7 7 8 10 10 12
where first three elements are genereted as follow
1+1 = 2
1+4 = 5
4+1 = 5
Edit:
I came up to this that the main problem is to find place for sum of elements with themselves. I will give example to make it more clear.
For sequence [1, 4, 10], we have
2 5 5 8 11 11 14 14 20
The problem is where to place sum of 4+4, that depends if 1+10 > 4+4, others sums have fixed place because second element + last will be always bigger than last + first (if we have elements in ascending order).

This can be solved in O(n log maxSum).
Pseudocode:
sort(array)
low = array[1] * 2
high = array[n] * 2
while (low <= high): (binarySearch between low and high)
mid = floor((high + low) / 2)
qty = checkHowManySumsAreEqualOrLessThan(mid)
if qty >= k:
high = mid - 1
else:
low = mid + 1
answer = low // low will be the first value of mid where qty was >= k. This means that on low - 1, qty was < k. This means the solution must be low
Sorting is O(n log n). Binary search costs log(array[n] * 2 - array[0] * 2).
checkHowManySumsAreEqualOrLessThan(mid) can be done in O(n) using 2 pointers, let me know if you can't figure out how.
This works because even though we are not doing the binary search over k, it is true that if there were x sums <= mid, if k < x then the kth sum would be lower than mid. Same for when k > x.

Thanks to juvian solving the hard parts, I was able to write this solution, the comments should explain it:
def count_sums_of_at_most(amount, nums1, nums2):
p1 = 0 # Pointer into the first array, start at the beginning
p2 = len(nums2) - 1 # Pointer into the second array, start at the end
# Move p1 up and p2 down, walking through the "diagonal" in O(n)
sum_count = 0
while p1 < len(nums1):
while amount < nums1[p1] + nums2[p2]:
p2 -= 1
if p2 < 0:
# p1 became too large, we are done
break
else:
# Found a valid p2 for the given p1
sum_count += p2 + 1
p1 += 1
continue
break
return sum_count
def find_sum(k, nums1, nums2):
# Sort both arrays, this runs in O(n * log(n))
nums1.sort()
nums2.sort()
# Binary search through all sums, runs in O(n * log(max_sum))
low = nums1[0] + nums2[0]
high = nums1[-1] + nums2[-1]
while low <= high:
mid = (high + low) // 2
sum_count = count_sums_of_at_most(mid, nums1, nums2)
if sum_count >= k:
high = mid - 1
else:
low = mid + 1
return low
arr = [1, 4, 5, 6]
for k in range(1, 1 + len(arr) ** 2):
print('sum', k, 'is', find_sum(k, arr, arr))
This prints:
sum 1 is 2
sum 2 is 5
sum 3 is 5
sum 4 is 6
sum 5 is 6
sum 6 is 7
sum 7 is 7
sum 8 is 8
sum 9 is 9
sum 10 is 9
sum 11 is 10
sum 12 is 10
sum 13 is 10
sum 14 is 11
sum 15 is 11
sum 16 is 12

Edit: this is O(n^2)
The way I understood the problem, the first number on the first row is the number of numbers, and the second number is k.
You can do this problem by using a PriorityQueue, which orders everything for you as you input numbers. Use 2 nested for loops such that they visit each pair once.
for(int k = 0; k < n; k++){
for(int j = 0; j <= k; j++){
If j==k, enter k+j into the PriorityQueue once, if not, enter the sum twice. Then, loop through the PriorityQueue to get he 6th value.
Will edit with full code if you'd like.

Related

sum of maximum element of sliding window of length K

Recently I got stuck in a problem. The part of algorithm requires to compute sum of maximum element of sliding windows of length K. Where K ranges from 1<=K<=N (N length of an array).
Example if I have an array A as 5,3,12,4
Sliding window of length 1: 5 + 3 + 12 + 4 = 24
Sliding window of length 2: 5 + 12 + 12 = 29
Sliding window of length 3: 12 + 12 = 24
Sliding window of length 4: 12
Final answer is 24,29,24,12.
I have tried to this O(N^2). For each sliding window of length K, I can calculate the maximum in O(N). Since K is upto N. Therefore, overall complexity turns out to be O(N^2).
I am looking for O(N) or O(NlogN) or something similar to this algorithm as N maybe upto 10^5.
Note: Elements in array can be as large as 10^9 so output the final answer as modulo 10^9+7
EDIT: What I actually want to find answer for each and every value of K (i.e. from 0 to N) in overall linear time or in O(NlogN) not in O(KN) or O(KNlogN) where K={1,2,3,.... N}
Here's an abbreviated sketch of O(n).
For each element, determine how many contiguous elements to the left are no greater (call this a), and how many contiguous elements to the right are lesser (call this b). This can be done for all elements in time O(n) -- see MBo's answer.
A particular element is maximum in its window if the window contains the element and only elements among to a to its left and the b to its right. Usefully, the number of such windows of length k (and hence the total contribution of these windows) is piecewise linear in k, with at most five pieces. For example, if a = 5 and b = 3, there are
1 window of size 1
2 windows of size 2
3 windows of size 3
4 windows of size 4
4 windows of size 5
4 windows of size 6
3 windows of size 7
2 windows of size 8
1 window of size 9.
The data structure that we need to encode this contribution efficiently is a Fenwick tree whose values are not numbers but linear functions of k. For each linear piece of the piecewise linear contribution function, we add it to the cell at beginning of its interval and subtract it from the cell at the end (closed beginning, open end). At the end, we retrieve all of the prefix sums and evaluate them at their index k to get the final array.
(OK, have to run for now, but we don't actually need a Fenwick tree for step two, which drops the complexity to O(n) for that, and there may be a way to do step one in linear time as well.)
Python 3, lightly tested:
def left_extents(lst):
result = []
stack = [-1]
for i in range(len(lst)):
while stack[-1] >= 0 and lst[i] >= lst[stack[-1]]:
del stack[-1]
result.append(stack[-1] + 1)
stack.append(i)
return result
def right_extents(lst):
result = []
stack = [len(lst)]
for i in range(len(lst) - 1, -1, -1):
while stack[-1] < len(lst) and lst[i] > lst[stack[-1]]:
del stack[-1]
result.append(stack[-1])
stack.append(i)
result.reverse()
return result
def sliding_window_totals(lst):
delta_constant = [0] * (len(lst) + 2)
delta_linear = [0] * (len(lst) + 2)
for l, i, r in zip(left_extents(lst), range(len(lst)), right_extents(lst)):
a = i - l
b = r - (i + 1)
if a > b:
a, b = b, a
delta_linear[1] += lst[i]
delta_linear[a + 1] -= lst[i]
delta_constant[a + 1] += lst[i] * (a + 1)
delta_constant[b + 2] += lst[i] * (b + 1)
delta_linear[b + 2] -= lst[i]
delta_linear[a + b + 2] += lst[i]
delta_constant[a + b + 2] -= lst[i] * (a + 1)
delta_constant[a + b + 2] -= lst[i] * (b + 1)
result = []
constant = 0
linear = 0
for j in range(1, len(lst) + 1):
constant += delta_constant[j]
linear += delta_linear[j]
result.append(constant + linear * j)
return result
print(sliding_window_totals([5, 3, 12, 4]))
Let's determine for every element an interval, where this element is dominating (maximum). We can do this in linear time with forward and backward runs using stack. Arrays L and R will contain indexes out of the domination interval.
To get right and left indexes:
Stack.Push(0) //(1st element index)
for i = 1 to Len - 1 do
while Stack.Peek < X[i] do
j = Stack.Pop
R[j] = i //j-th position is dominated by i-th one from the right
Stack.Push(i)
while not Stack.Empty
R[Stack.Pop] = Len //the rest of elements are not dominated from the right
//now right to left
Stack.Push(Len - 1) //(last element index)
for i = Len - 2 to 0 do
while Stack.Peek < X[i] do
j = Stack.Pop
L[j] = i //j-th position is dominated by i-th one from the left
Stack.Push(i)
while not Stack.Empty
L[Stack.Pop] = -1 //the rest of elements are not dominated from the left
Result for (5,7,3,9,4) array.
For example, 7 dominates at 0..2 interval, 9 at 0..4
i 0 1 2 3 4
X 5 7 3 9 4
R 1 3 3 5 5
L -1 -1 1 -1 4
Now for every element we can count it's impact in every possible sum.
Element 5 dominates at (0,0) interval, it is summed only in k=1 sum entry
Element 7 dominates at (0,2) interval, it is summed once in k=1 sum entry, twice in k=2 entry, once in k=3 entry.
Element 3 dominates at (2,2) interval, it is summed only in k=1 sum entry
Element 9 dominates at (0,4) interval, it is summed once in k=1 sum entry, twice in k=2, twice in k=3, twice in k=4, once in k=5.
Element 4 dominates at (4,4) interval, it is summed only in k=1 sum entry.
In general element with long domination interval in the center of long array may give up to k*Value impact in k-length sum (it depends on position relative to array ends and to another dom. elements)
k 1 2 3 4 5
--------------------------
5
7 2*7 7
3
9 2*9 2*9 2*9 9
4
--------------------------
S(k) 28 32 25 18 9
Note that the sum of coefficients is N*(N-1)/2 (equal to the number of possible windows), the most of table entries are empty, so complexity seems better than O(N^2)
(I still doubt about exact complexity)
The sum of maximum in sliding windows for a given window size can be computed in linear time using a double ended queue that keeps elements from the current window. We maintain the deque such that the first (index 0, left most) element in the queue is always the maximum of the current window.
This is done by iterating over the array and in each iteration, first we remove the first element in the deque if it is no longer in the current window (we do that by checking its original position, which is also saved in the deque together with its value). Then, we remove any elements from the end of the deque that are smaller than the current element, and finally we add the current element to the end of the deque.
The complexity is O(N) for computing the maximum for all sliding windows of size K. If you want to do that for all values of K from 1..N, then time complexity will be O(N^2). O(N) is the best possible time to compute the sum of maximum values of all windows of size K (that is easy to see). To compute the sum for other values of K, the simple approach is to repeat the computation for each different value of K, which would lead to overall time of O(N^2). Is there a better way ? No, because even if we save the result from a computation for one value of K, we would not be able to use it to compute the result for a different value of K, in less then O(N) time. So best time is O(N^2).
The following is an implementation in python:
from collections import deque
def slide_win(l, k):
dq=deque()
for i in range(len(l)):
if len(dq)>0 and dq[0][1]<=i-k:
dq.popleft()
while len(dq)>0 and l[i]>=dq[-1][0]:
dq.pop()
dq.append((l[i],i))
if i>=k-1:
yield dq[0][0]
def main():
l=[5,3,12,4]
print("l="+str(l))
for k in range(1, len(l)+1):
s=0
for x in slide_win(l,k):
s+=x
print("k="+str(k)+" Sum="+str(s))

Tips in optimizing an algorithm

I'll try to phrase this question without making it sound like I am seeking for homework answers (this is just a practice problem for algorithms)
you have an array of numbers where every value can occur at most 2x [1 3 5 2 5 1 2 3]
Examine sums from one value to the other instance of itself (5 + 2 + 5) (2 + 5 + 1 + 2)
Find an algorithm that finds the max of such sum.
I came up with a pretty simple algorithm:
iterate through the array (for i=1 to n)
iterate through the remaining array (for j=i+1)
if A[i] == A[j]
s = 0
iterate through the values between those two points (for k=i to j)
s = s + A[k]
maxVal = max(maxVal,s)
What are some steps I can take towards optimizing the algorithm. (or any algorithm for that matter). Obviously this solution is the first that came to mind but I am having trouble envisioning better solutions that would be more efficient.
Edit: For sake of the problem I'll just say all elements are postitive
Calculate array of cumulative sums:
C[0] = A[0]
for i = 1 to n
C[i] = C[i - 1] + A[i]
A[1 3 5 2 5 1 2 3]
C[0 1 4 9 11 16 17 19 22]
Use these values when pair found:
Sum(i to j) = C[j] - C[i - 1]
P.S. Are all elements always positive?
You can get rid of the most inner loop by pre calculate all the sum from index 1 to index i and store it into an array, call sum. So if you want to get the sum between i and j, the result will be sum[j] - sum[i - 1].
for(i = 1 to n)
sum[i] = A[i];
if(i - 1 > 1)
sum[i] += sum[i - 1];
Also notice that there are only two occurrences for each value in the array, we can remember the first position of this value using a map/dictionary or an array pos (if possible) and if we saw it again , we can use it to calculate the sum between the first and this position.
pos[];
for(i = 1 to n)
if(pos[A[i]] ==0)
pos[A[i]] = i;
else
result = max(result,sum[i] - sum[pos[A[i]] - 1])
So in total, the time complexity of this will be O(n)

How to generate the continuous sequence which sum up equal to N [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
Given a number N and generate an Arithmetic Progression having difference of 1 so that after summing up to finite element gives the number N
for example:
For Example:
N=10
1 + 2 + 3 + 4 =10
N=20
2+3+4+5+6 = 20
N=30
4+5+6+7+8 = 30
N < 1000000
Start with sum = 0.
Let 1 be the current number.
Add the current number to the sum.
If sum > N, subtract numbers from the first number added to the sum until sum <= N.
Stop if sum = N (success).
Increase the current number.
Continue from step 3.
You'll just need to remember the first number added to the sum for step 4, which you will increase by one as you subtract it from the sum (thanks Niko).
As an optimization, you can also use a formula (n(n+1)/2) to add numbers in batch rather than adding them one by one (in case N is large).
Example:
N = 30
Sum = 0
Add 1 -> 1
Add 2 -> 3
Add 3 -> 6
Add 4 -> 10
Add 5 -> 15
Add 6 -> 21
Add 7 -> 28
Add 8 -> 36
36 > 30, so:
Subtract 1 -> 35
Subtract 2 -> 33
Subtract 3 -> 30
Done.
Let T be the number
So N(N+1)/2 = T in your first case where N=4
N(N+1)/2 - K(K+1)/2 = T in your second case where N=6 & K=1
N(N+1)/2 - K(K+1)/2 = T in your third case where N=8 & K=3
So you solve for N basically that is by multiplying & reducing you get
N^2 + N - (2T + K^2 + K) = 0
Applying quadratic formula for N that is
N= (-b + sqrt(b^2 - 4ac))/2a
So we get,
N = (-1 +- sqrt(1 + 8T + 4K^2 + 4K))/2
N has to be positive so we can remove the negative case
Therefore N has to be equal to
N = (sqrt(8T + (2k+1)^2) - 1)/2
You can iterate from K=0 till you get a natural number N which will be your answer
Hope it helps, Iam trying to find a better way as iam doing this(appreciate the interesting problem)
Let N = pq where p is an odd positive integer and q is any positive integer.
(1) You can write N as sum of p consecutive integers, with q as the middle value.
(2) And if both p and q are odd (say, q = 2k+1), you can also write N as sum of 2p consecutive integers, with k and k+1 in the middle.
For example, let N = 15 = 5 x 3.
If we choose p=5, then following rule (1) we have 1+2+3+4+5 = 15.
Or by rule (2) we could also write (-3)+(-2)+(-1)+0+1+2+3+4+5+6 = 15.
We can also choose p = 3 to get 4+5+6 = 15 and 0+1+2+3+4+5 = 15 too.
int NumSum(int val)
{
int n = 0, i = 0, j;
while (n != val)
{
n = 0;
j = ++i;
while (n < val)
n += j++;
}
return i;
}
No fancy maths, just the easy way of doing it.. Returns number to start counting from.
This is more of a trick method & i think it might work.
Lets say number is 10 then start a sequence from n/2 that is 5
Now the sequence cannot be
5+6 since 10>11 so we have to work backwards also 5 is the upper limit of numbers we need to consider since numbers like 6+7 etc will exceed 10 so the last number(highest) of the sequence will be 5.
moving backwards 5+4=9 < 10
5+4+3=12 > 10 so remove first element kinda like a queue.
So for 20 we have
start = 20/2 = 10
10 + 9 = 19 -> do nothing
10 + 9 + 8 = 27 -> remove first element that is 10
9 + 8 + 7 = 24 -> remove 9
8 + 7 + 6 = 21 -> remove 8
7 + 6 + 5 = 18 -> do nothing
7 + 6 + 5 + 4 = 22 -> remove 7
6 + 5 + 4 + 3 = 18 -> do nothing
6 + 5 + 4 + 3 + 2 = 20 -> Answer we need
I guess this is a variation to the accepted answer but still thought i could add this as an alternative solution.
First, every odd number is the sum of an AP length 2 because n = floor(n/2) + ceil(n/2).
More interestingly, a number with an odd divisor d is a sum of an AP length d (with difference 1) around n/d. For instance, 30 is divisible by 5, so is the sum of an AP around 6: 30 = 4 + 5 + 6 + 7 + 8.
A number with no odd divisors is a power of 2. While 1 = 0 + 1 and 2 = -1 + 0 + 1 + 2, larger powers are not the sum of any (non-trivial) arithmetic progression. Why? Suppose 2**m = a + (a+1) + .. + (a+k-1). Sum the series = k (2a + k-1) / 2. k must be odd or even, but either choice contradicts the sum being a power of 2.

What is a better method to solve this prob?

Here is the problem i am trying to solve,
You are given a table with 2 rows and N columns. Each cell has an integer in it. The score
of such a table is denfined as follows: for each column, consider the sum of the two numbers
in the column; the maximum of the N numbers so obtained is the score. For example, for
the table
7 1 6 2
1 2 3 4
the score is max(7 + 1; 1 + 2; 6 + 3; 2 + 4) = 9.
The first row of the table is fixed, and given as input. N possible ways to ll the second
row are considered:
1; 2; : : : ; N
2; 3; : : : ; N; 1
3; 4; : : : ; N; 1; 2
|
N; 1; : : : ; ; N 1
For instance, for the example above, we would consider each of the following as possibilities for the second row.
1 2 3 4
2 3 4 1
3 4 1 2
4 1 2 3
Your task is to find the score for each of the above choices of the second row. In the
example above, you would evaluate the following four tables,
7 1 6 2
1 2 3 4
7 1 6 2
2 3 4 1
7 1 6 2
3 4 1 2
7 1 6 2
4 1 2 3
and compute scores 9, 10, 10 and 11, respectively
Test data: N <= 200000
Time Limit: 2 seconds
Here is the obvious method:
Maintain two arrays A,B, Do the following n times
add every element A[i] to B[i] and keep a variable max which stores the maximum value so far.
print max
loop through array B[i] and increment all the elements by 1, if any element is equal to N, set it equal to 1.
This method will have take O(n^2) time, the outer loop runs N times and there are two inner loops which run for N times each.
To reduce the time taken, we can find the maximum element M in the first row(in a linear scan), and then remove A[i] and B[i] whenever A[i] + N <= M + 1.
Because they will never be max.
But this method might perform better in the average case, the worst case time will still be O(N^2).
To find max in constant time i also considered using a heap, each element of the heap has two attributes, their original value and the value to be added.
But still it will require a linear time to increment the value-to-be-added for all the elements of the heap for each of the n cases.
And so the time still remains O(N^2)
I am not able to find a method that will solve this problem faster than N^2 time which will be too slow as the value of N can be very large.
Any help would be greatly appreciated.
There is also an O(n) algorithm. Using the same observations as in a previous answer:
Now consider what happens to the column sums when you rotate the second row to the left (e.g. change it from 1,2,...,N to 2,3,...,N,1): Each column sum will increase by 1, except for one column sum which is decreased by N-1.
Instead of modifying all the column sums, we can decrease the one column sum by N, and then take the maximum column sum plus 1 to find the new maximum of the column sums. So we only need to update one column instead of all of them.
The column where the maximum appears can only move to the left or jump back to the column with the overall maximum as we iterate over the possibilities of the second row. Candidate columns are the ones that were the temporary maximum in a left to right maximum scan.
calculate all the sums for the first choice of the second row (1, 2, ..., N) and store them in an array.
find the maximum in this array in a left to right scan and remember the positions of temporary maxima.
in a right to left pass the sums are now decreased by N. If this decreasing process reaches the max column, check if the number is smaller than the overall maximum - N, in this case the new max column is the overall maximum column and it will stay there for the rest of the loop. If the number is still larger than the previous maximum determined in step 2, the max column will stay the same for the rest of the loop. Otherwise, the previous maximum becomes the new max column.
Taking the example input 7,1,6,2 the algorithm runs as follows:
Step 1 calculates the sum 8,3,9,6
Step 2 finds the temporary maxima from left to right: 8 in col 1 and then 9 in col 3
Step 3 generates the results passing over the array from right to left
8 3 9 6 -> output 9 + 0 = 9
8 3 9 2 -> output 9 + 1 = 10
8 3 5 2 -> current max col is decreased, previous max 8 is larger and becomes current
output 8 + 2 = 10
8 -1 5 2 -> output 8 + 3 = 11
Here is the algorithm in C:
#include <stdio.h>
int N;
int A[200000];
int M[200000];
int main(){
int i,m,max,j,mval,mmax;
scanf("%d",&N);
for(i = 0;i < N; i++){
scanf("%d",&A[i]);
A[i] = A[i]+i+1;
}
m = 0;
max = 0;
M[0] = 0;
for(i = 1;i < N; i++){
if(A[i] > A[max]){
m++;
M[m] = i;
max = i;
}
}
mval = A[max] - N;
mmax = max;
for(i = N-1,j = 0;i >=0;i --,j++){
printf("%d ", A[max]+j);
A[i] = A[i] - N;
if(i == max){
if (A[i] < mval) {
max = mmax;
} else if(m > 0 && A[i] < A[M[m-1]]){
max = M[m-1];
m--;
}
}
}
printf("\n");
return 0;
}
Here is an O(n*logn) solution:
Suppose you calculate all the column sums for a particular arrangement of the second row.
Now consider what happens to the column sums when you rotate the second row to the left (e.g. change it from 1,2,...,N to 2,3,...,N,1): Each column sum will increase by 1, except for one column sum which is decreased by N-1.
Instead of modifying all the column sums, we can decrease the one column sum by N, and then take the maximum column sum plus 1 to find the new maximum of the column sums. So we only need to update one column instead of all of them.
So our algorithm would be:
Set the second row to be 1,2,...,N and calculate the sum of each column. Put all these sums in a max-heap. The root of the heap will be the largest sum.
For i in 1 to N:
Decrease the value of the heap node corresponding to the N-i th column by N.
The new maximum column sum is the root of the heap plus i.
Each heap update takes O(logn) which leads to an O(n*logn) overall time.

modifying Euler Totient Function

to calculate the number of integers co-prime to N and less than N we can simply calculate its ETF . However to calcuate the number of integers co-prime to N but less then M where M < N , how can we modify / calculate it ?
I have tried the code to calcuate the ETF but can't proceed how to modify it to get the required result.
Code:
int etf(int n)
{
int result = n;
int i;
for(i=2;i*i <= n;i++)
{
if (n % i == 0) result -= result / i;
while (n % i == 0) n /= i;
}
if (n > 1) result -= result / n;
return result;
}
Thanks
You need to use the inclusion-exclusion principle. Let's do an example: suppose you want to calculate the amount of integers coprime to 30 = 2 * 3 * 5 and smaller than 20.
The first thing to note is that you can count the numbers that are not coprime to 30 and subtract them from the total instead, which is a lot easier. The number of multiples of 2 less than 20 is 20/2 = 10, the number of multiples of 3 is 20/3 = 6 (taking the floor), and the number of multiples of 5 is 20/5 = 4.
However, note that we counted numbers such as 6 = 2 * 3 more than once, both in the multiples of 2 and the multiples of 3. To account for that, we have to subtract every number that is a multiple of the product of two primes.
This, on the other hand, subtracts numbers that are multiples of three of the primes once more than necessary -- so you have to add that count to the end. Do it like this, alternating signs, until you reach the total number of primes that divide N. In the example, the answer would be
20/1 - 20/2 - 20/3 - 20/5 + 20/2*3 + 20/3*5 + 20/2*5 - 20/2*3*5
= 20 - 10 - 6 - 4 + 3 + 1 + 2 - 0
= 6.
(The numbers we're counting are 1, 7, 11, 13, 17 and 19.)

Resources