卡丹尔算法(max subarray problem)

来源:互联网 发布:禁止网游软件 编辑:程序博客网 时间:2024/06/07 08:57

问题介绍

Say you have an array for which the ith element is the price of a
given stock on day i. If you were only permitted to complete at most
one transaction (ie, buy one and sell one share of the stock), design
an algorithm to find the maximum profit.

抽象出来就是找到一个数组nums[0,n]的子数组 nums[i, j] (0 <=i < j <= n) 使得 nums[j] - nums[i]取得最大值。当然可以直接使用暴力解法,复杂度为O(n*n)。但是有一个更为聪明的办法,可以将复杂度降解为O(n), 这就是非常有名的卡丹尔算法。求解思路很简洁,本质是动态规划的思想,只需要维护一个dp数组,记录子数组结束于当前位置i时的最大值, 因为一定要包含位置i, 故有dp[i] = dp[i - 1] + nums[i] - nums[i - 1]。根据题意有dp[i]的最小值是0,因此 dp[i] = max(0, dp[i - 1] + nums[i] - nums[i - 1]),遍历dp数组找到一个最大值即可。可以进一步进行优化,在扫描nums数组的时候使用max_ending_here表示dp[i], 使用max_so_far维护max_ending_here所有出现的值中的最大值,从而将空间复杂度从O(n)降解为O(1)

求解

#include <stdio.h>#include <stdlib.h>#include <assert.h>int * newIntRaw(int n){    return (int *)malloc(sizeof(int) * n);}int max(int a, int b){    return a > b ? a : b;}int maxProfit1(int *prices, int pricesSize){    int max_ending_here = 0, max_so_far = 0;    int i;    for (i = 1; i < pricesSize; ++i) {        max_ending_here += prices[i] - prices[i - 1];        max_ending_here = max(0, max_ending_here);        max_so_far = max(max_ending_here, max_so_far);    }    return max_so_far;}int maxProfit(int *prices, int pricesSize){    int *dp;    int res = 0;    int i;    if (pricesSize <= 0)        return 0;    dp = newIntRaw(pricesSize);    dp[0] = 0;    for (i = 1; i < pricesSize; ++i) {        dp[i] = max(0, dp[i - 1] + prices[i] - prices[i - 1]);        res =  max(res, dp[i]);    }    free(dp);    return res;}int main(){    int i;    int n;    int *nums;    scanf("%d", &n);    nums = newIntRaw(n);    for (i = 0; i < n; ++i)        scanf("%d", &nums[i]);    printf("%d\n", maxProfit(nums, n));    free(nums);    return 0;}

类似问题

Maximum Subarray:
Find the contiguous subarray within an array (containing at least one number) which has the largest sum.

For example, given the array [-2,1,-3,4,-1,2,1,-5,4],
the contiguous subarray [4,-1,2,1] has the largest sum = 6.

求解思路与上一题一直,直接上代码:

#include <stdio.h>#include <stdlib.h>int * newIntRaw(int n){    return (int *)malloc(sizeof(int) * n);}int max(int a, int b){    return a > b ? a : b;}int maxSubArray(int *nums, int numsSize){    int maxEndingHere, maxCur;    int i;    if (numsSize <= 0)        return 0;    maxEndingHere = maxCur = nums[0];    for (i = 1; i < numsSize; ++i) {        maxEndingHere = max(maxEndingHere + nums[i], nums[i]);        maxCur = max(maxCur, maxEndingHere);    }    return maxCur;}int main(){    int n;    int *nums;    int i;    scanf("%d", &n);    nums = newIntRaw(n);    for (i = 0; i < n; ++i) {        scanf("%d", &nums[i]);    }    printf("%d\n", maxSubArray(nums, n));    free(nums);    return 0;}/*9-2 1 -3 4 -1 2 1 -5 4*/
原创粉丝点击