【面试题】数对之差的最大值

转自:

http://zhedahht.blog.163.com/blog/static/2541117420116135376632/

 

问题描述:

在数组中,数字减去它右边的数字得到一个数对之差。求所有数对之差的最大值。例如在数组{2, 4, 1, 16, 7, 5, 11, 9}中,数对之差的最大值是11,是16减去5的结果。

 

解法一:分治法

我们可以想象,数对之差的最大值只有可能是下面三种情况之一:(1)被减数和减数都在第一个子数组中,即第一个子数组中的数对之差的最大值;(2)被减数和减数都在第二个子数组中,即第二个子数组中数对之差的最大值;(3)被减数在第一个子数组中,是第一个子数组的最大值。减数在第二个子数组中,是第二个子数组的最小值。这三个差值的最大者就是整个数组中数对之差的最大值。

 

//求一个数组中
#include <iostream>
using namespace std;

int MaxDiffCore(int* start, int* end, int* max, int* min)
{
    if(end == start)
    {
        *max = *min = *start;
        return 0x80000000;
    }
    int* middle = start + (end - start) / 2;
    int maxLeft, minLeft;
	//递归调用,求出左半部分的最大差值
    int leftDiff = MaxDiffCore(start, middle, &maxLeft, &minLeft);
    int maxRight, minRight;
	//递归调用,求出右半部分的最大差值
    int rightDiff = MaxDiffCore(middle + 1, end, &maxRight, &minRight);
	//求出
    int crossDiff = maxLeft - minRight;
    *max = (maxLeft > maxRight) ? maxLeft : maxRight;
    *min = (minLeft < minRight) ? minLeft : minRight;
    int maxDiff = (leftDiff > rightDiff) ? leftDiff : rightDiff;
    maxDiff = (maxDiff > crossDiff) ? maxDiff : crossDiff;
    return maxDiff;
}

int MaxDiff_Solution1(int numbers[], unsigned length)
{
    if(numbers == NULL || length < 2)
	{
		return 0;
	}
    int max, min;
    return MaxDiffCore(numbers, numbers + length - 1, &max, &min);
}

void main()
{
	int a[]={2,4,1,16,7,5,11,9};
	int b = MaxDiff_Solution1(a,sizeof(a)/sizeof(a[0]));
	cout << b <<endl;
}

 


解法二:转化成求解子数组的最大和问题

如果输入一个长度为n的数组numbers,我们先构建一个长度为n-1的辅助数组diff,并且diff[i]等于numbers[i]-numbers[i+1]0<=i<n-1)。如果我们从数组diff中的第i个数字一直累加到第j个数字(j > i),也就是diff[i] + diff[i+1] + … + diff[j] = (numbers[i]-numbers[i+1]) + (numbers[i + 1]-numbers[i+2]) + ... + (numbers[j] – numbers[j + 1]) = numbers[i] – numbers[j + 1]

 

分析到这里,我们发现原始数组中最大的数对之差(即numbers[i] – numbers[j + 1])其实是辅助数组diff中最大的连续子数组之和。

 

//求一个数组中
#include <iostream>
using namespace std;

int MaxDiff_Solution2(int numbers[], unsigned length)
{
    if(numbers == NULL || length < 2)
	{
		return 0;
	}
    int* diff = new int[length - 1];
    for(int i = 1; i < length; ++i)
	{
		diff[i - 1] = numbers[i - 1] - numbers[i];
	}
    int currentSum = 0;
    int greatestSum = 0x80000000;
    for(int i = 0; i < length - 1; ++i)
    {
        if(currentSum <= 0)
		{
            currentSum = diff[i];
		}
        else
		{
            currentSum += diff[i];
		}
        if(currentSum > greatestSum)
		{
			greatestSum = currentSum;
		}
    }
    delete[] diff;
    return greatestSum;
} 

void main()
{
	int a[]={2,4,1,16,7,5,11,9};
	int b = MaxDiff_Solution2(a,sizeof(a)/sizeof(a[0]));
	cout << b <<endl;
}


 解法三:动态规划法

我们定义diff[i]是以数组中第i个数字为减数的所有数对之差的最大值。也就是说对于任意hh < i),diff[i]≥number[h]-number[i]diff[i]0≤i<n)的最大值就是整个数组最大的数对之差。

假设我们已经求得了diff[i],我们该怎么求得diff[i+1]呢?对于diff[i],肯定存在一个hh < i),满足number[h]减去number[i]之差是最大的,也就是number[h]应该是number[i]之前的所有数字的最大值。当我们求diff[i+1]的时候,我们需要找到第i+1个数字之前的最大值。第i+1个数字之前的最大值有两种可能:这个最大值可能是第i个数字之前的最大值,也有可能这个最大值就是第i个数字。第i+1个数字之前的最大值肯定是这两者的较大者。我们只要拿第i+1个数字之前的最大值减去number[i+1],就得到了diff[i+1]

 

 

//求一个数组中
#include <iostream>
using namespace std;

int MaxDiff_Solution3(int numbers[], unsigned length)
{
    if(numbers == NULL || length < 2)
	{
		return 0;
	}
    int max = numbers[0];
    int maxDiff =  max - numbers[1];
    for(int i = 2; i < length; ++i)
    {
        if(numbers[i - 1] > max)
		{
            max = numbers[i - 1];
		}
        int currentDiff = max - numbers[i];
        if(currentDiff > maxDiff)
		{
			maxDiff = currentDiff;
		}
    }
    return maxDiff;
}

void main()
{
	int a[]={2,4,1,16,7,5,11,9};
	int b = MaxDiff_Solution3(a,sizeof(a)/sizeof(a[0]));
	cout << b <<endl;
}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值