Divide and Conquer to find maximum difference in an array - c++

I am trying to solve a problem where given an array I need to calculate the maximum difference such that the larger element appears after the smaller element.
Here is a better problem statement:
Given the stock prices on each day for n days, what is the maximum profit a person can make by doing exactly one transaction. One transaction means that the person can buy exactly one stock on one day and sell it on a later date.
I am trying to solve this problem using divide and conquer algo.
In my recursive function i am trying to spilt the array into two halves, but i am not sure on how to proceed with logic. Do i just get the max difference in each halves and compare?
int calculateMaxDiff(int *src, int start, int end){
if(end - start == 1) return src[start];
int middle = (start + end)/ 2;
int half1_diff;
int half2_diff;
half1_diff = calculateMaxDiff(src, start, middle);
half2_diff = calculateMaxDiff(src, middle, end);
//Do i need to have two loops here that calculate the diffs for each halves
....
return max(half1_diff, half2_diff);
}
Edit: Example output
Give an array {12, 9, 18, 3, 7, 11, 6, 15, 6, 1 ,10} should return 12 as a result of difference between 15 and 3

The question in your problem can be translated into a better problem statement:
Given the stock prices on each day for n days, what is the maximum profit a person can make by doing exactly one transaction. One transaction means that the person can buy exactly one stock on one day and sell it on a later date.
The divide-and-conquer solution: Let's see if we can solve this by splitting the input in half, solving the problem in each subarray, then combining the two together. Turns out we actually can do this, and can do so efficiently! The intuition is as follows. If we have a single day, the best option is to buy on that day and then sell it back on the same day for no profit. Otherwise, split the array into two halves. If we think about what the optimal answer might be, it must be in one of three places:
The correct buy/sell pair occurs completely within the first half.
The correct buy/sell pair occurs completely within the second half.
The correct buy/sell pair occurs across both halves - we buy in the first half, then sell in the second half.
We can get the values for (1) and (2) by recursively invoking our algorithm on the first and second halves. For option (3), the way to make the highest profit would be to buy at the lowest point in the first half and sell in the greatest point in the second half. We can find the minimum and maximum values in the two halves by just doing a simple linear scan over the input and finding the two values. This then gives us an algorithm with the following recurrence:
T(n) = 2T(n/2) + O(n)
T(n) = O(nlogn)
Here is a simple implementation in Python. Its very simple to understand and its also easy to convert to C++:
def DivideAndConquerSingleSellProfit(arr):
# Base case: If the array has zero or one elements in it, the maximum
# profit is 0.
if len(arr) <= 1:
return 0;
# Cut the array into two roughly equal pieces.
left = arr[ : len(arr) / 2]
right = arr[len(arr) / 2 : ]
# Find the values for buying and selling purely in the left or purely in
# the right.
leftBest = DivideAndConquerSingleSellProfit(left)
rightBest = DivideAndConquerSingleSellProfit(right)
# Compute the best profit for buying in the left and selling in the right.
crossBest = max(right) - min(left)
# Return the best of the three
return max(leftBest, rightBest, crossBest)
Edit: Here is the C++ implementation for the above algorithm
#include <iostream>
#include <algorithm>
using namespace std;
int calculateMin(int a[], int low, int high)
{
int i,mini;
mini = a[low];
for(i=low;i<=high;i++)
{
if(a[i]<mini)
{
mini = a[i];
}
}
return mini;
}
int calculateMax(int a[], int low, int high)
{
int i,maxi;
maxi = a[low];
for(i=low;i<=high;i++)
{
if(a[i]>maxi)
{
maxi = a[i];
}
}
return maxi;
}
int calculateMaxDiff(int a[], int low, int high)
{
if(low>=high)
return 0;
int mid = (low+high)/2;
int leftPartition = calculateMaxDiff(a,low,mid);
int rightPartition = calculateMaxDiff(a,mid+1,high);
int left = calculateMin(a,low,mid); // calculate the min value in the left partition
int right = calculateMax(a,mid+1,high); // calculate the max value in the right partition
return max(max(leftPartition, rightPartition), (right - left));
}
int main() {
int arr[] = {12, 9, 18, 3, 7, 11, 6, 15, 6, 1 ,10};
int len = sizeof(arr)/sizeof(arr[0]);
int ans = calculateMaxDiff(arr, 0, len-1);
cout << "Maximum Profit: " <<ans<<endl;
return 0;
}
Hope it helps!!!

There is no need in complicated D/C algorithm because simple cycle with checking like
maxdiff = max(current - min_so_far, maxdiff)
update min_so_far
solves the problem
If you really want to apply divide and conquer method, you may return triplet {local_min, local_max, local_max_diff} from recursive function like:
left = calculateMaxDiff(start, middle)
right = calculateMaxDiff(middle + 1, end)
return {min(left.local_min, right.local_min),
max(left.local_max, right.local_max),
max(left.local_diff, right.local_diff, right.localmax - left.local_min)

The key for a divide and conquer algorithm is the conquer part.
For this problem the most important condition is:
the larger element appears after the smaller element
For an array src, after dividing src to 2 halves, half1 and half2, suppose the answer would be in position i and j, there are 3 cases now:
i and j are both in half1 -> half1_diff
i and j are both in half2 -> half2_diff
i is in half1 and j is in half2
So the main part is to deal with case3. As the larger one comes after, so we just need to find the minimum value min_half1 in half1 and the maximum value max_half2 in half2, and check if it meets the condition max_half2 >= min_half1 and update the result as max(half1_diff, half2_diff, max_half2-min_half1).
In order to calculate min_half1 and max_half2 efficiently, you have to keep the record of min and max value of the array, and it takes O(1) time.
So T(n) = 2T(n/2) + O(1), T(n) = O(n).
Check the example for more details
http://ideone.com/TbIL2r

Related

Does this recursive algorithm for finding the largest sum in a continuous sub array have any advantages?

Objective: Evaluating the algorithm for finding the largest sum in a continuous subarray below.
Note: written in C++
As I was looking into the problem that Kadane successfully solved using dynamic programming, I thought I would find my own way of solving it. I did so by using a series of recursive calls depending on whether the sum can be larger by shorting the ends of the array. See below.
int corbins_largest_sum_continuous_subarray(int n, int* array){
int sum = 0; // calculate the sum of the current array given
for(int i=0; i<n; i++){sum += array[i];}
if(sum-array[0]>sum && sum-array[n-1]>sum){
return corbins_largest_sum_continuous_subarray(n-2, array+1);
}else if(sum-array[0]<sum && sum-array[n-1]>sum){
return corbins_largest_sum_continuous_subarray(n-1, array);
}else if(sum-array[0]>sum && sum-array[n-1]<sum){
return corbins_largest_sum_continuous_subarray(n-1, array+1);
}else{
return sum; // this is the largest subarray sum, can not increase any further
}
}
I understand that Kadane's algorithm takes O(n) time. I am having trouble calculating the Big O of my algorithm. Would it also be O(n)? Since it calculates the sum using O(n) and all calls after that use the same time. Does my algorithm provide any advantage over Kadane's? In what ways is Kadane's algorithm better?
First of all, the expression sum-array[0]>sum is equivalent to array[0]<0. A similar observation applies to those other conditions you have in your code.
Your algorithm is incorrect. The comment you have here is not true:
}else{
return sum // this is the largest subarray sum, can not increase any further
}
When you get at that point you know that the outer two values are both positive, but there might be a negative-sum subarray somewhere else in the array, which -- when removed -- would give two remaining subarrays, of which one (or both) could have a sum that is greater than the total sum.
For instance, the following input would be such a case:
[1, -4, 1]
Your algorithm will conclude that the maximum sum is achieved by taking the complete array (sum is -2), yet the subarray [1] represents a greater sum.
Other counter examples:
[1, 2, -2, 1]
[1, -3, -3, 1, 1]

Multiple Constrain Knapsack

I'm trying to solve the following problem:
INPUT:
An array of items, each item has 3 different weights (integers), a value and the amount available of this type of item.
A maximum for each type of weight
OUTPUT:
An array that tells how many of each item to take in order to achieve the maximum value. The sum of each of the weights of every item must not exceed the maximum allowed and you may not take more of an item of what is available.
Example output: {3,0,2,1} means 3 of item1, 0 of item2, 2 of item3, and 1 of item4.
Example scenario:
In case I wasn't very clear with the explanation, imagine it's about putting food on a backpack. Each type of food has a weight, a volume, a number of calories and a value and there's a certain amount of each type of food available. The objective would be to maximize the value of the food in the backpack without exceeding a certain maximum amount of weight, volume and calories.
On this scenario the INPUT could be:
Array<Food>:
Burger (Weight 2, Volume 2, Calories 5, Value 5$, number of Burgers 3)
Pizza (Weight 3, Volume 7, Calories 6, Value 8$, number of Pizzas 2)
Hot Dog (Weight 1, Volume 1, Calories 3, Value 2$, number of Hot Dogs 6)
int MaxWeight = 10; int MaxVolume = 15; int MaxCalories = 10;
My Attempt
Since the data set is quite small (say 7 types of items and there's no more than 15 pieces of each item available), I thought of a brute force search:
Keep track of the best set found so far (Most value and doesn't
exceed any limits), call best set B
Have a recursive function R(s) which takes a set (array of how many of each item) as input, if the input is invalid, it returns. If the input is valid it first updates B (in case s better than B) and then calls R(s + p_i) for every product p_i
The idea is to first call R(s) with s = empty set (0 for every product) and every possible branch will be created while the branches that exceed the weights are ignored.
This obviously didn't work cause the amount of branches that have to be checked is huge even for only as few as 7 items
Any help is much appreciated!
You have to consider each type of weight in your DP method. I'll write the implementation in C++:
vector<Food> Array;
int memo[MAX_ITEM][MAX_WEIGHT1][MAX_WEIGHT2][MAX_WEIGHT3];
int f(int ind, int weight1, int weight2, int weight3){
if(weight1<0 || weight2<0 || weight3<0) return -INF;
if(ind == Array.size()) return 0;
int &ret= memo[ind][weight1][weight2][weight3];
if(ret>0) return ret;
int res = 0;
for(int i=0;i<=Array[ind].maxOfType;i++)
res = max(res, i * Array[ind].value + f(ind+1, weight1-i*Array[ind].weight1, weight2-i*Array[ind].weight2, weight3-i*Array[ind].weight3));
return ret = res;
}
The DP function is recursive and we use memoization to optimize it. It returns the maximum value we can get. you can call it by:
f(0,MaxWeight1, MaxWeight2, MaxWeight3);
After that we have to track and see which items leads to maximum value. The Next method will print what you want:
void printResult(int ind, int weight1, int weight2, int weight3){
if(ind == Array.size()) return;
int maxi = memo[ind][weight1][weight2][weight3];
for(int i=0;i<=Array[ind].maxOfType;i++){
int cur = i * Array[ind].value + f(ind+1, weight1-i*Array[ind].weight1, weight2-i*Array[ind].weight2, weight3-i*Array[ind].weight3);
if(cur == maxi){
cout<<i<<", ";
printResult(ind+1, weight1-i*Array[ind].weight1, weight2-i*Array[ind].weight2, weight3-i*Array[ind].weight3);
break;
}
}
}
All codes are tested and works well.

minimum total move to balance array if we can increase/decrease a specific array element by 1

It is leetcode 462.
I have one algorithm but it failed some tests while passing others.
I tried to think through but not sure what is the corner case that i overlooked.
We have one array of N elements. One move is defined as increasing OR decreasing one single element of the array by 1. We are trying to find the minimum number of moves to make all elements equal.
My idea is:
1. find the average
2. find the element closest to the average
3. sum together the difference between each element and the element closest to the average.
What am i missing? Please provide one counter example.
class Solution {
public:
int minMoves2(vector<int>& nums) {
int sum=0;
for(int i=0;i<nums.size();i++){
sum += nums[i];
}
double avg = (double) sum / nums.size();
int min = nums[0];
int index =0 ;
for(int i=0;i<nums.size();i++){
if(abs(nums[i]-avg) <= abs(min - avg)){
min = nums[i];
index = i;
}
}
sum=0;
for(int i=0;i<nums.size();i++){
sum += abs(min - nums[i]);
}
return sum;
}
};
Suppose the array is [1, 1, 10, 20, 100]. The average is a bit over 20. So your solution would involving 19 + 19 + 10 + 0 + 80 moves = 128. What if we target 10 instead? Then we have 9 + 9 + 0 + 10 + 90 moves = 118. So this is a counter example.
Suppose you decide to target changing all array elements to some value T. The question is, what's the right value for T? Given some value of T, we could ask if increasing or decreasing T by 1 will improve or worsen our outcome. If we decrease T by 1, then all values greater than T need an extra move, and all those below need one move less. That means that if T is above the median, there are more values below it than above, and so we benefit from decreasing T. We can make the opposite argument if T is less than the median. From this we can conclude that the correct value of T is actually the median itself, which my example demonstreates (strictly speaking, when you have an even sized array, T can be anywhere between the two middle elements).

Is Coin Change Algorithm That Output All Combinations Still Solvable By DP?

For example, total amount should be 5 and I have coins with values of 1 and 2. Then there are 3 ways of combinations:
1 1 1 1 1
1 1 1 2
1 2 2
I've seen some posts about how to calculate total number of combinations with dynamic programming or with recursion, but I want to output all the combinations like my example above. I've come up with a recursive solution below.
It's basically a backtracking algorithm, I start with the smallest coins first and try to get to the total amount, then I remove some coins and try using second smallest coins ... You can run my code below in http://cpp.sh/
The total amount is 10 and the available coin values are 1, 2, 5 in my code.
#include <iostream>
#include <stdlib.h>
#include <iomanip>
#include <cmath>
#include <vector>
using namespace std;
vector<vector<int>> res;
vector<int> values;
int total = 0;
void helper(vector<int>& curCoins, int current, int i){
int old = current;
if(i==values.size())
return;
int val = values[i];
while(current<total){
current += val;
curCoins.push_back(val);
}
if(current==total){
res.push_back(curCoins);
}
while (current>old) {
current -= val;
curCoins.pop_back();
if (current>=0) {
helper(curCoins, current, i+1);
}
}
}
int main(int argc, const char * argv[]) {
total = 10;
values = {1,2,5};
vector<int> chosenCoins;
helper(chosenCoins, 0, 0);
cout<<"number of combinations: "<<res.size()<<endl;
for (int i=0; i<res.size(); i++) {
for (int j=0; j<res[i].size(); j++) {
if(j!=0)
cout<<" ";
cout<<res[i][j];
}
cout<<endl;
}
return 0;
}
Is there a better solution to output all the combinations for this problem? Dynamic programming?
EDIT:
My question is is this problem solvable using dynamic programming?
Thanks for the help. I've implemented the DP version here: Coin Change DP Algorithm Print All Combinations
A DP solution:
We have
{solutions(n)} = Union ({solutions(n - 1) + coin1},
{solutions(n - 2) + coin2},
{solutions(n - 5) + coin5})
So in code:
using combi_set = std::set<std::array<int, 3u>>;
void append(combi_set& res, const combi_set& prev, const std::array<int, 3u>& values)
{
for (const auto& p : prev) {
res.insert({{{p[0] + values[0], p[1] + values[1], p[2] + values[2]}}});
}
}
combi_set computeCombi(int total)
{
std::vector<combi_set> combis(total + 1);
combis[0].insert({{{0, 0, 0}}});
for (int i = 1; i <= total; ++i) {
append(combis[i], combis[i - 1], {{1, 0, 0}});
if (i - 2 >= 0) { append(combis[i], combis[i - 2], {{0, 1, 0}}); }
if (i - 5 >= 0) { append(combis[i], combis[i - 5], {{0, 0, 1}}); }
}
return combis[total];
}
Live Demo.
Exhaustive search is unlikely to be 'better' with dynamic programming, but here's a possible solution:
Start with a 2d array of combination strings, arr[value][index] where value is the total worth of the coins. Let X be target value;
starting from arr[0][0] = "";
for each coin denomination n, from i = 0 to X-n you copy all the strings from arr[i] to arr[i+n] and append n to each of the strings.
for example with n=5 you would end up with
arr[0][0] = "", arr[5][0] = "5" and arr[10][0] = "5 5"
Hope that made sense. Typical DP would just count instead of having strings (you can also replace the strings with int vector to keep count instead)
Assume that you have K the total size of the output your are expecting (the total number of coins in all the combinations). Obviously you can not have a solution that runs faster than O(K), if you actually need to output all them. As K can be very large, this will be a very long running time, and in the worst case you will get little profit from the dynamic programming.
However, you still can do better than your straightforward recursive solution. Namely, you can have a solution running in O(N*S+K), where N is the number of coins you have and S is the total sum. This will not be better than straightforward solution for the worst possible K, but if K is not so big, you will get it running faster than your recursive solution.
This O(N*S+K) solution can be relatively simply coded. First you run the standard DP solution to find out for each sum current and each i whether the sum current can be composed of first i coin types. You do not yet calculate all the solutions, you just find out whether at least one solution exists for each current and i. Then, you write a recursive function similar to what you have already written, but before you try each combination, you check using you DP table whether it is worth trying, that is, whether at least one solution exists. Something like:
void helper(vector<int>& curCoins, int current, int i){
if (!solutionExists[current, i]) return;
// then your code goes
this way each branch of the recursion tree will finish in finding a solution, and therefore the total recursion tree size will be O(K), and the total running time will be O(N*S+K).
Note also that all this is worth only if you really need to output all the combinations. If you need to do something else with the combinations you get, it is very probable that you do not actually need all the combinations and you may adapt the DP solution for that. For example, if you want to print only m-th of all solutions, this can be done in O(N*S).
You just need to make two passes over the data structure (a hash table will work well as long as you've got a relatively small number of coins).
The first one finds all unique sums less than the desired total (actually you could stop perhaps at 1/2 the desired total) and records the simplest way (least additions required) to obtain that sum. This is essentially the same as the DP.
The second pass then goes starts at the desired total and works its way backwards through the data to output all ways that the total can be generated.
This ends up being a two stage approach of what Petr is suggesting.
The actual amount of non distinct valid combinations for amounts {1, 2, 5} and N = 10 is 128, using a pure recursive exhaustive technique (Code below). My question is can an exhaustive search be improved with memoization/dynamic programming. If so, how can I modify the algorithm below to incorporate such techniques.
public class Recursive {
static int[] combo = new int[100];
public static void main(String argv[]) {
int n = 10;
int[] amounts = {1, 2, 5};
ways(n, amounts, combo, 0, 0, 0);
}
public static void ways(int n, int[] amounts, int[] combo, int startIndex, int sum, int index) {
if(sum == n) {
printArray(combo, index);
}
if(sum > n) {
return;
}
for(int i=0;i<amounts.length;i++) {
sum = sum + amounts[i];
combo[index] = amounts[i];
ways(n, amounts, combo, startIndex, sum, index + 1);
sum = sum - amounts[i];
}
}
public static void printArray(int[] combo, int index) {
for(int i=0;i < index; i++) {
System.out.print(combo[i] + " ");
}
System.out.println();
}
}

How to return the correct value when Divide and Conquer Algorithm(for 1-D Closest Pairs) has done its job?

I need to find the closest pair of numbers of an integer array. For example: If I have {25, 13, 59, 7, 16} numbers, my result should be |13 - 16| = 3. So I try to solve the problem using Divide and Conquer Algorithm. But when I get differences of numbers from sub-problems, I can't store and compare them. I see where my program goes wrong when I debug it but couldn't find any solution for hours.
Here is my function:
int closestPairs(int list[], int first, int last)
{
if (last - first == 1)
return 0;
else if (last - first == 2)
return abs(list[first] - list[last - 1]);
int median = (first + last) / 2;
int left = closestPairs(list, first, median);
int right = closestPairs(list, median, last);
int temp = abs(list[first] - list[last - 1]);
if (abs(left - right) < temp)
temp = abs(left - right);
return temp;
}
And here is the driver function:
int main()
{
int list[] = { 34, 23, 48 , 4, 66, 69};
int n = sizeof(list) / sizeof(int);
cout << closestPairs(list, 0, n) << endl;
return 0;
}
So how can I store the value obtained from abs(left - right) and see if it's less or greater than the next value? Or am I wrong all over and doing everything wrong? Thanks in advance.
It seems to me that the concepts of using recursion to find the solution and storing a value for comparison to the next iteration are opposing concepts in this case. Storing a variable for comparison in a recursive function seems like it would be a bit of a mess (and require some significant restructuring of your code). The idea as I understand it of your divide and conquer algorithm is to take a big list of ints and divide it into smaller lists and allowing the best possible answer to make its way up through the chain. Here's the way I see this working based on your code (using mostly pseudo code):
int FindClosest(int list[],int first,int last)
{
if(number of elements in list == 2)
{
return (int2 - int1)
}
if(number of elements in list == 3){
{
if((int3-int2)<(int2 - int2))
return (int3-int2)
else
return (int2-int1)
}
if(number of elements in list >3)
{
subList1 = oneSubGroupofElements(list)
subList2 = anotherSubGroupofelements(list)
if(FindClosest(subList1)<FindClosest(subList2))
return Findclosest(subList1)
else
return FindClosest(subList2)
}
}
There is another issue with this method which you can see for lists with more than 2 elements, that is because your result relies on pairwise neighbours, you must consider that you can't just split the list in half. For example:
int list[] = {1,4,5,9}
would cause problems if you simply split the list into two lists of two elements as the difference between 4 and 5 would not be considered (which would be the correct answer). Your sublists would have to include the overlap so that at least one of the sublists returns 5-4 when called from FindClosest.
You have to sort the list before finding the closest pair using the divide and conquer technique. Because that eliminates many corner cases.