数对之差的最大值

题目摘自何海涛的http://zhedahht.blog.163.com/题目中,自己按照作者的思路重新实现了代码,作者用了3中方法,这里我也按照他的思路把代码写了一遍。


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


源代码放在附件上。

.h文件:

/************************************************************************/
/* 在数组中,数字减去它右边的数字得到一个数对之差。求所有数对之差的最大值。
例如在数组{2, 4, 1, 16, 7, 5, 11, 9}中,数对之差的最大值是11,是16减去5的结果。                                                                     */
/************************************************************************/
int maxDiff_Solution1(int number[], int length);
int maxDiffCore(int *start, int *end, int &max, int &min);


int maxDiff_Solution2(int numbers[], int length);
int maxDiff_Solution3(int numbers[], int length);
 

.cpp文件:

#include "stdafx.h"
#include "maxdiff.h"

/************************************************************************/
/* 采用分治算法查找最大差值:
假设我们把数组分成两个子数组,我们其实没有必要拿左边的子数组中较小的数字去
和右边的子数组中较大的数字作减法。我们可以想象,数对之差的最大值只有可能是下面三种情况之一:
(1)被减数和减数都在第一个子数组中,即第一个子数组中的数对之差的最大值;
(2)被减数和减数都在第二个子数组中,即第二个子数组中数对之差的最大值;
(3)被减数在第一个子数组中,是第一个子数组的最大值。
减数在第二个子数组中,是第二个子数组的最小值。这三个差值的最大者就是整个数组中数对之差的最大值。*/
/************************************************************************/
int maxDiff_Solution1(int number[], int length)
{
	if(number == NULL || length < 2) return -1;

	int max = 0;
	int min = 0;
	return maxDiffCore(number, number + length - 1, max, min);
}


int maxDiffCore(int *start,int *end, int &max, int &min)
{
	if(start == end)
	{
		max = min = *start;
		return 0x80000000;
	}

	int *middle = start + (end - start) / 2;

	int leftMax, leftMin;
	int leftMaxDiff = maxDiffCore(start, middle, leftMax, leftMin);

	int rightMax, rightMin;
	int rightMaxdiff = maxDiffCore(middle + 1, end, rightMax, rightMin);

	max = leftMax > rightMax ? leftMax : rightMax;
	min = leftMin < rightMin ? leftMin : rightMin;

	int crossDiff = leftMax - rightMin;

	int MaxDiff = leftMaxDiff > rightMaxdiff ? leftMaxDiff : rightMaxdiff;
	MaxDiff = MaxDiff > crossDiff ? MaxDiff : crossDiff;

//	cout<<MaxDiff<<endl;

	return MaxDiff;
}

/************************************************************************/
/* 转化成求解子数组的最大和问题:如果输入一个长度为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中最大的连续子数组之和。
我们在本系列的博客的第3篇《求子数组的最大和》中已经详细讨论过这个问题的解决方法。                                                                     */
/************************************************************************/
int maxDiff_Solution2(int numbers[], int length)
{
	int *diff = new int[length - 1];

	memset(diff, 0, length - 1);
#ifdef DEBUG
	cout<<"*********************"<<endl;
#endif
	for(int i = 0; i < length - 1; ++i)
	{
		diff[i] = numbers[i] - numbers[i + 1];
		cout<<diff[i]<<endl;
		
	}
#ifdef DEBUG
	cout<<"*************"<<endl;
#endif

	int maxDiff = 0;
	int currNumber = 0;
	for(int i = 0; i < length - 1; ++i)
	{
		if(currNumber <= 0)
			currNumber = diff[i];
		else
			currNumber += diff[i];

		if(currNumber > maxDiff) maxDiff = currNumber;
	}

	delete []diff;

	return maxDiff;
}

/************************************************************************/
/* 转化成求解子数组的最大和问题:

10000(被减数) —(减号) 6000(减数) =(等于号) 4000(差)

既然我们可以把求最大的数对之差转换成求子数组的最大和,而子数组的最大和可以通过动态规划求解,
那我们是不是可以通过动态规划直接求解呢?下面我们试着用动态规划法直接求数对之差的最大值。

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

假设我们已经求得了diff[i],我们该怎么求得diff[i+1]呢?
对于diff[i],肯定存在一个h(h < 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]。*/
/************************************************************************/
int maxDiff_Solution3(int numbers[], int length)
{
	if(numbers == NULL || length < 2) return - 1;

	int maxNumber = numbers[0];
	int maxDiff = maxNumber - numbers[1];
	
	for(int i = 2; i < length; ++i)
	{
		if(maxNumber < numbers[i - 1]) maxNumber = numbers[i - 1];

		int diff = maxNumber - numbers[i];
		if(diff > maxDiff) maxDiff = diff;
	}

	return maxDiff;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值