我正在尝试解决一个问题,在给定数组的情况下,我需要计算最大差异,使较大的元素出现在较小的元素之后。
这是一个更好的问题陈述:
鉴于n
天每天的股票价格,一个人通过一次交易可以获得的最大利润是多少。一笔交易意味着该人可以在一天内购买一只股票并在以后出售。
我试图用分而治之的算法来解决这个问题。
在我的递归函数中,我试图将数组分成两半,但我不确定如何继续逻辑。我只是得到每一半的最大差异并进行比较吗?
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);
}
修改:示例输出
给出一个数组{12,9,18,3,7,11,6,15,6,1,10}应该返回12由于15和3之间的差异
答案 0 :(得分:3)
您问题中的问题可以转化为更好的问题陈述:
考虑到n天内每天的股票价格,一个人通过一次交易可以获得的最大利润是多少。一笔交易意味着该人可以在一天内购买一只股票并在以后出售。
分而治之的解决方案:让我们看看我们是否可以通过将输入分成两半来解决这个问题,解决每个子阵列中的问题,然后将两者结合起来。事实证明我们实际上可以做到这一点,并且可以有效地做到这一点!直觉如下。如果我们有一天,最好的选择是在当天购买,然后在同一天将其卖回,无利可图。否则,将阵列分成两半。如果我们考虑最佳答案可能是什么,它必须在三个地方之一:
我们可以通过在第一和第二半递归调用我们的算法来获得(1)和(2)的值。对于选项(3),获得最高利润的方式是在上半年的最低点买入,在下半年卖出最高点。我们可以通过对输入进行简单的线性扫描并找到两个值来找到两半的最小值和最大值。然后,这给我们一个具有以下重现的算法:
T(n) = 2T(n/2) + O(n)
T(n) = O(nlogn)
这是Python中的一个简单实现。它很容易理解,也很容易转换为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)
编辑:以下是上述算法的C ++实现
#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;
}
希望它有所帮助!!!
答案 1 :(得分:2)
没有必要使用复杂的D / C算法,因为简单的循环与检查如
maxdiff = max(current - min_so_far, maxdiff)
update min_so_far
解决问题
如果你真的想要应用分而治之的方法,你可以从递归函数返回三元组{local_min, local_max, local_max_diff}
,如:
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)
答案 2 :(得分:1)
分而治之算法的关键是征服部分。
对于这个问题,最重要的条件是:
较小的元素出现在较小的元素
之后
对于数组src
,在将src
分为两半half1
和half2
后,假设答案位于i
和{{ 1}},现在有3个案例:
j
和i
都在j
- &gt; half1
half1_diff
和i
都在j
- &gt; half2
half2_diff
位于i
,half1
位于j
所以主要部分是处理case3。随着更大的值出现,我们只需找到half2
中的最小值min_half1
和half1
中的最大值max_half2
,并检查它是否符合条件half2
并将结果更新为max_half2 >= min_half1
。
为了有效地计算max(half1_diff, half2_diff, max_half2-min_half1)
和min_half1
,您必须保留数组的max_half2
和min
值的记录,并且需要{{1}时间。
所以max
,O(1)
。
查看示例以获取更多详细信息