数组中两个数相减(相加)的最大值

题目:有一个数组,找出数组中前面的数减去后面的数的最大值。例如数组{9,1,7,18,3,-2,20,4,0,5},最大值是18-(-2)或者20-0。

解法一:把数组分为左右两个部分,相减最大的两个数可能产生于左半部分,右半部分,或者横跨左右两个部分,最大值为这三种情况中数值最大的那个。对于两个数位于左右两部分的情况,最大的结果应该是左半部分的最大值减右半部分的最小值;左半部分和右半部分又可以各自划分成两部分,递归的求出最大值。时间复杂度O(nlogn).

int GetMaxCore(int *arr, int left, int right)
{
    if(left == right)
        return arr[left];

    int mid = (left+right)/2;
    int maxOfLeftSub = GetMaxCore(arr, left, mid);
    int maxOfRightSub = GetMaxCore(arr, mid+1, right);
    int maxOfLeft = INT_MIN;
    int minOfRight = INT_MAX;
    for(int i = left; i <= mid; ++i)
    {
        if(arr[i] > maxOfLeft)
            maxOfLeft = arr[i];
    }

    for(int i = mid+1; i <= right; ++i)
    {
        if(arr[i] < minOfRight)
            minOfRight = arr[i];
    }
    
    int tmp = maxOfLeftSub > maxOfRightSub ? maxOfLeftSub : maxOfRightSub;
    return tmp > (maxOfLeft-minOfRight) ? tmp : (maxOfLeft-minOfRight);
}

int GetMaxOfFormerSubLatter(int * arr, int n)
{
    return GetMaxCore(arr, 0, n-1);
}

解法二:使用两个指针,初始值设为指向第一个数和第二个数,如下图所示:


p1,p2指向前两个数,初始的最大值就是max=9-1=8。然后p1保持不变,移动p2指针,每移动一次计算p1指向的值和p2指向的值之差,如果大于max,则更新max,直到p2指向第一个大于p1的值。


这时候再拿p1减去p2后面的值就没有意义了,因为p1<p2,拿p1减p2后面的值肯定不会比p2减去它后面的值大。因此我们把指针p1指向p2的位置,p2后移一位。如下图所示,直到p2到达数组末尾。


这里面跳过了第二幅图中p1和p2中间的数相减的情况,当p1指向9,p2指向18,9和18之间的两个数相减有没有可能更大呢?可以证明不存在这种情况。假设p1和p2之间存在两个数n1和n2有n1-n2更大,由于p2是第一个大于p1的数,所以n1<p1,,那么p1-n2>n1-n2,矛盾,可知这种情况不存在。时间复杂度O(n).

代码如下:

int GetMaxOfFormerSubLatter(int * arr, int n)
{
    int p1 = 0;
    int p2 = 1;
    int max = arr[p1] - arr[p2];
    while(p2 < n)
    {
        while(arr[p2] < arr[p1] && p2 < n)
        {
            if(arr[p1] - arr[p2] > max)
                max = arr[p1] - arr[p2];
            ++p2;
        }
        p1 = p2;
        ++p2;
    }

    return max;
}

解法三:试想遍历数组时,如果当前数作为被减数,那么前面的数和它相减要取得最大值应该拿前面最大的那个数和它减,扫描到当前值前面的最大值是可以记录下来的。设前面某个数减去当前值的最大值为max,而数组中当前值左边的数的最大值为maxOfLeft。每扫描到一个数,计算maxOfLeft减去当前值,并与max比较,如果大则更新max。在指针移向下一个值之前更新左边部分的数的最大值maxOfLeft。时间复杂度O(n).

int GetMaxOfFormerSubLatter(int * arr, int n)
{
    int max = arr[0] - arr[1];
    int maxOfLeft = arr[0];
    for(int i = 1; i < n; ++i)
    {
        int tmp = maxOfLeft - arr[i];
        if(tmp > max)
            max = tmp;
        if(arr[i] > maxOfLeft)
            maxOfLeft = arr[i];
    }

    return max;
}

扩充:对于两个数相加的最大值,思路完全类似,可以将解法三中的“-”号改成“+”号就可以了。






  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值