Finding largest sum in an unsorted array using divide and conquer algorithm - algorithm

I have a sequence of n real numbers stored in a array, A[1], A[2], …, A[n]. I am trying to implement a divide and conquer algorithm to find two numbers A[i] and A[j], where i < j, such that A[i] ≤ A[j] and their sum is the largest.
For eg. {2, 5, 9, 3, -2, 7} will give the output of 14 (5+9, not 16=9+7). Can anyone suggest me some ideas on how to do it?
Thanks in advance.

This problem is not really suited to a divide and conquer approach. It's easy to observe that if (i, j) is a solution for this problem, then A[j] >= A[k] for every k > j, i.e A[j] is the maximum in A[j..n]
Prove: if there exists such k > j and A[k] > A[j], then (j, k) is a better solution than (i, j)
So we only need to consider js that satisfies that criteria.
Algorithm (pseudo-code)
maxj = n
for (j = n - 1 down to 1):
if (a[j] > a[maxj]) then:
maxj = j
else:
check if (j, maxj) is a better solution
Complexity: O(n)
C++ implementation: http://ideone.com/ENp5WR (The implementation use an integer array, but it should be the same for floats)

Declare two variables, during your algorithm check if the current number is bigger than either of the two values currently be stored in the variables, if yes replace the smallest, if not, continue.

Here's a recursive solution in Python. I wouldn't exactly call it "divide and conquer" but then again, this problem isn't very suited to a divide and conquer approach.
def recurse(lst, pair): # the remaining list left to process
if not lst: return # if lst is empty, return
for i in lst[1:]: # for each elements in lst starting from index 1
curr_sum = lst[0] + i
if lst[0] < i and curr_sum > pair[0]+pair[1]: # if the first value is less than the second and curr_sum is greater than the max sum so far
pair[0] = lst[0]
pair[1] = i # update pair to contain the new pair of values that give the max sum
recurse(lst[1:], pair) # recurse on the sub list from index 1 to the end
def find_pair(s):
if len(s) < 2: return s[0]
pair = [s[0],s[1]] # initialises pair array
recurse(s, pair) # passed by reference
return pair
Sample output:
s = [2, 5, 9, 3, -2, 7]
find_pair(s) # ============> (5,9)

I think you can just use an algorithm in O(n) as described follow
(The merge part uses constant time)
Here is the outline of the algorithm:
Divide the problem into two half: LHS & RHS
Each half should returned the largest answer meeting the requirement in that half AND the largest element in that half
Merge and return the answer to upper level: answer is the maximum of LHS's answer, RHS's answer, and the sum of the largest element in both half (consider this only if RHS's largest element >= LHS's largest element)
Here is the demonstration of the algorithm using your example: {2, 5, 9, 3, -2, 7}
Divide into {2,5,9}, {3,-2,7}
Divide into {2,5}, {9}, {3,-2}, {7}
{2,5} return max(2,5, 5+2) = 7, largest element = 5
{9} return 9, largest element = 9
{3,-2} return max(3,-2) = 3, largest element = 3
{7} return 7, largest element = 7
{2,5,9} merged from {2,5} & {9}: return max(7,9,9+5) = 14, largest element = max(9,5) = 9
{3,-2,7} merged from {3,-2} & {7}: return max(3,7,7+3) = 10, largest element = max(7,3) = 7
{2,5,9,3,-2,7} merged from {2,5,9} and {3,-2,7}: return max(14,10) = 14, largest element = max(9,7) = 9
ans = 14
Special cases like {5,4,3,2,1} which yields no answer needs extra handling but not affecting the core part and the complexity of the algorithm.

Related

kth smallest number

Suppose we have n (1<=n<=10^3) sorted arrays of sizes A1, A2, .... An. (1<=Ai<=10^3). We need to kind the kth smallest integer from the unique combination these arrays. Is there an efficient method to do this with complexity less than O(A1 + A2.. + An)?
Can be be solved something similar to binary search?
PS: I have a similar problem here, but could not understand how to extend it for unique elements.
EDIT 1: I think some of you misunderstood the question. Let us take an example:
N = 3,
A1 = 1, 1, 2, 3
A2 = 6, 7, 9
A3 = 1, 6, 8
The unique combination of above arrays is {1, 2, 3, 6, 7, 8, 9}. Now suppose I want the 2nd element it should return 2 and for 4th element it should return 6.
It is possible in O(k n log n):
Make a min-heap with the minimal element from each array.
Repeat k times:
Look at the minimum element q in the min-heap and remember it
Extract from min-heap while minimum equals to q.
For each extracted element, put the first element larger than q from the corresponding array
Answer is the minimum element in min-heap
Python code:
import heapq
import bisect
def kth(A, k):
h = []
for idx,a in enumerate(A):
if len(a) > 0:
heapq.heappush(h, (a[0], idx))
for i in xrange(k):
if len(h) == 0:
return None
val, _ = h[0]
while (len(h) > 0) and (h[0][0] == val):
_, idx = heapq.heappop(h)
nxt = bisect.bisect_right(A[idx], val)
if nxt < len(A[idx]):
heapq.heappush(h, (A[idx][nxt], idx))
if len(h) > 0:
return h[0][0]
return None
Is there a space requirement, or can the numbers in the arrays be duplicated?
If not, you could create 2 sorted sets: uniques and nonUniques.
When adding an array, you loop over the array and add its numbers to the 2 sorted sets like this:
If a new number exists in nonUniques, skip it
If a number exists in uniques, remove it from uniques and add it to nonUniques
Otherwise add the nww number to uniques
Then you can immediately look up the k-th smallest number in the sorted uniques set.

Number of Contigious subarrays satisfying constraints

Given array A , find number of continious sub arrays which satisfies condition:
There is no pair (i,j) in the subarray such that i < j and A[i] mod A[j]= M
1<=A[i]<=100000
My Approach: Do it naive way in O(n^2) time complexity, which is bad.
Can I reduce it to (nlogn) ?
This is a O(N) time complexity, but requires O(N+M) space complexity:
We scan the array and perform A[i] = A[i] mod M
Keep a counter array of size N which keeps track of how many elements before it respect the given condition (basically not being the equal to the current element):
C[i] = the number of elements A[j], such that A[j]!=A[i] where j
Consider the array:
Original A array: 12, 25, 16, 14, 37, 18, 28, 17, 9, 37
New A array: 0, 1, 4, 2, 1, 6, 4, 5, 9, 1 (A[i] mod M)
Counter array: 0, 1, 2, 3, 2, 3, 3, 4, 5, 4
The counter array can be constructed incrementally based on previous values:
A[j] = A[i] and j
Otherwise C[i] = C[i-1]+1;
When looking for the last occurrence of A[i] before index i, we need to keep a dictionary (A[i], last-index-of-A[i]) for fast lookup.
Since we keep only values for A[i] mod M => a O(M) dictionary will do.
We now just sum up the counter array values:
Number of contiguous subarrays = Sum(C)
In this case we will have 27 contiguous subarrays that respect this condition.
Basically, we need to find all pairs such that i < j and A[i] mod A[j] = M
If a mod b = m, then a mod d = m, where d is a divisor of b and d > m
Hash the numbers in the array. For each number a in the array, check if a - m or any of the divisors of a - m are elements in the array and their index is greater than the index of a - enumerate any existing pairs (a, a - m) or (a, divisor of (a - m) > m) in O(n sqrt n).
Clearly, any contiguous sub-arrays satisfying the condition lie between any such pairs. If we aggregate the pairs in an interval tree, as we traverse the array, we can test if we are within a pair in O(log n) time. Once we detect we are overlapping a pair (an interval in the tree), we reset our window to (i + 1, j) (where (i,j) is the interval) and keep counting; we add to the total the largest segments achievable according to the formula, segment * (segment + 1) / 2, subtracted by the previous overlapping count.

count no. of pairs such that absolute difference is less than K

Given an array A of size N, how do I count the number of pairs(A[i], A[j]) such that the absolute difference between them is less than or equal to K where K is any positive natural number? (i, j<=N and i!=j)
My approach:
Sort the array.
Create another array that stores the absolute difference between two consecutive numbers.
Am I heading in the right direction? If yes, then how do I proceed further?
Here is a O(nlogn) algorithm :-
1. sort input
2. traverse the sorted array in ascending order.
3. for A[i] find largest index A[j]<=A[i]+k using binary search.
4. count = count+j-i
5. do 3 to 4 all i's
Time complexity :-
Sorting : O(n)
Binary Search : O(logn)
Overall : O(nlogn)
This is O(n^2):
Sort the array
For each item_i in array,
For each item_j in array such that j > i
If item_j - item_i <= k, print (item_j, item_i)
Else proceed with the next item_i
Your approach is partially correct. You first sort the array. Then keep two pointers i and j.
1. Initialize i = 0, j = 1.
2. Check if A[j] - A[i] <= K.
- If yes, then increment j,
- else
- **increase the count of pairs by C(j-i,2)**.
- increment i.
- if i == j, then increment j.
3. Do this till pointer j goes past the end of the array. Then just add C(j-1,2) to the count and stop.
By i and j, you are basically maintaining a window within which the difference between elements is <= K.
EDIT: This is the basic idea, you will have to check for boundary conditions. Also you will have to keep track of the past interval that was added to the count. You will need to subtract the overlap with the current interval to avoid double counting.
Complexity: O(NlogN), for the sort operation, linear for the array traversal
Once your array is sorted, you can compute the sum in O(N) time.
Here's some code. The O(N) algorithm is pair_sums, and pair_sums_slow is the obviously correct, but O(N^2) algorithm. I run through some test cases at the end to make sure that the two algorithms returns the same results.
def pair_sums(A, k):
A.sort()
counts = 0
j = 0
for i in xrange(len(A)):
while j < len(A) and A[j] - A[i] <= k:
j+=1
counts += j - i - 1
return counts
def pair_sums_slow(A, k):
counts = 0
for i in xrange(len(A)):
for j in xrange(i+1, len(A)):
if A[j] - A[i] <= k:
counts+=1
return counts
cases = [
([0, 1, 2, 3, 4, 5], 10),
([0, 0, 0, 0, 0], 1),
([0, 1, 2, 4, 8, 16], 9),
([0, -1, -2, 1, 2], 2)
]
for A, k in cases:
want = pair_sums_slow(A, k)
got = pair_sums(A, k)
if want != got:
print A, k, want, got
The idea behind pair_sums is that for each i, we find the smallest j such that A[j] - A[i] > K (or j=N). Then j-i-1 is the number of pairs with i as the first value.
Because the array is sorted, j only ever increases as i increases, so the overall complexity is linear since although there's nested loops the inner operation j+=1 can occur at most N times.

Find a single number in a list when other numbers occur more than twice

The problem is extended from Finding a single number in a list
If I extend the problem to this:
What would be the best algorithm for finding a number that occurs only once in a list which has all other numbers occurring exactly k times?
Does anyone have good answer?
for example, A = { 1, 2, 3, 4, 2, 3, 1, 2, 1, 3 }, in this case, k = 3. How can I get the single number "4" in O(n) time and the space complexity is O(1)?
If every element in the array is less n and greater than 0.
Let the array be a, traverse the array for each a[i] add n to a[(a[i])%(n)].
Now traverse the array again, the position at which a[i] is less than 2*n and greater than n (assuming 1 based index) is the answer.
This method won't work if at least on element is greater than n. In that case you have to use method suggested by Jayram
EDIT:
To retrieve the array just apply mod n to every element in the array
This can be solved in given with your constraints if the numbers other than lonely number are occurring exactly in even count (i.e. 2, 4, 6, 8...) by doing the XOR operation on all the numbers.
But other than this in space complexity O(1) its just teasing me.
If other than your given constraints you could use these approaches to solve this.
Sort the numbers and have a current variable to get the count of current number. If it is greater than 1 then go to next number and so on. Space O(1)...Time O(nlogn)
Use O(n) extra memory to count the occurrences of each number. Time O(n)...Space O(n)
I Just want to extend #banarun answer .
Take the input as map . Like a[0]=1; Then take it as myMap with 0 as index and 1 as value .
And while reading the input find the maximum number M . Then find A prime greater than M as P.
No iterate through the map and for every key i of myMap add P to myMap(myMap(i)%P) if myMap(myMap(i)%P) is not initiated set it to P. Now iterate through the myMap again, the position at which myMap[i] is >=P And < 2*P is your answer. Basically the the Idea is to remove overflow and overwrite problem from the banarun suggested Algo .
Here is an mechanism which may not be as good as the others but which is instructive and gets to the core of why the XOR answer is as good as it is when k = 2.
1. Represent each number in base k. Support there are at most r digits in the representation
2. Add each of the numbers in the right-most ('r'th) digit mod k, then 'r - 1'st digit (mod k) and so on
3. The final representation of r digits that you have is the answer.
For example, if the array is
A = {1, 2, 3, 4, 2, 3, 1, 2, 1, 3, 5, 4, 4}
Representation in mod 3 is
A = {01, 02, 10, 11, 02, 10, 01, 02, 01, 10, 12, 11, 11}
r = 2
Sum of 'r'th place = 2
Sum of the 'r-1'th place = 1
Hence answer = {12} in base 3 which is 5.
This is an answer which will be O(n * r). Note that r is proportional to log n.
Why is the XOR answer in O(n) ? Because the processor provides an XOR operation which is performed in O(1) time rather than the O(r) factor that we have above.
According to banarun solution(with small fix's):
Algorithm conditions:
for each i arr[i]<N (size of array)
for each i arr[i]>=0 (positive)
The Algorithm:
int[] arr = { 1, 2, 3, 4, 2, 3, 1, 2, 1, 3 };
for (int i = 0; i < arr.Length; i++)
{
arr[(arr[i])%(arr.Length)] += arr.Length;
if(arr[i] < arr.Length)
arr[i] = -1;
}
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] - 3 * arr.Length <0 && arr[i]!=-1)
Console.WriteLine("single number = "+i);
}
This solution is with Time complexity of O(N) And Space complexity of O(1)
Note:
Again this algorithm can work only if all number are positives and all numbers are less then N.

Finding largest from each subarray of length k

Interview Question :- Given an array and an integer k , find the maximum for each and every contiguous sub array of size k.
Sample Input :
1 2 3 1 4 5 2 3 6
3 [ value of k ]
Sample Output :
3
3
4
5
5
5
6
I cant think of anything better than brute force. Worst case is O(nk) when array is sorted in decreasing order.
Just iterate over the array and keep k last elements in a self-balancing binary tree.
Adding element to such tree, removing element and finding current maximum costs O(logk).
Most languages provide standard implementations for such trees. In STL, IIRC, it's MultiSet. In Java you'd use TreeMap (map, because you need to keep count, how many times each element occurs, and Java doesn't provide Multi- collections).
Pseudocode
for (int i = 0; i < n; ++i) {
tree.add(a[i]);
if (tree.size() > k) {
tree.remove(a[i - k]);
}
if (tree.size() == k) {
print(tree.max());
}
}
You can actually do this in O(n) time with O(n) space.
Split the array into blocks of each.
[a1 a2 ... ak] [a(k+1) ... a2k] ...
For each block, maintain two more blocks, the left block and the right block.
The ith element of the left block will be the max of the i elements from the left.
The ith element of the right block will be the max of the i elements from the right.
You will have two such blocks for each block of k.
Now if you want to find the max in range a[i... i+k], say the elements span two of the above blocks of k.
[j-k+1 ... i i+1 ... j] [j+1 ... i+k ... j+k]
All you need to do is find the max of RightMax of i to j of the first block and the left max of j+1 to i+k of the second block.
Hope this is the solution which you are looking for:
def MaxContigousSum(lst, n):
m = [0]
if lst[0] > 0:
m[0] = lst[0]
maxsum = m[0]
for i in range(1, n):
if m[i - 1] + lst[i] > 0:
m.append(m[i - 1] + lst[i])
else:
m.append(0)
if m[i] > maxsum:
maxsum = m[i]
return maxsum
lst = [-2, 11, -4, 13, -5, 2, 1, -3, 4, -2, -1, -6, -9]
print MaxContigousSum(lst, len(lst))
**Output**
20 for [11, -4, 13]

Resources