求数组两两之差绝对值最小的值

一 题目描述:

  有一个整数数组,请求出两两之差绝对值最小的值,只要求出最小值即可,不要求求出是哪两个数。

  二 常规思路:

  求解此题的寻常思路是什么?观察题目我注意到后面强调不要求求出两个数,那么最最简单的O(n^2)的

算法显然做了很多无用功。嗯,好,既然这个办法不行想想其他的。对于数组也就是序列之类的题,有一种很

常用的思路那就是预处理。这道题目貌似是可以的。

  首先,对数组进行排序,这个可以在O(n*logn)时间之类解决,然后,有了这个预处理,就会想到,绝对值

之差最小值肯定只能发生在预处理的数组之后的相邻的元素上,这个是很显然的事实。那么我们便可以循环一

遍数组,记下两两之间绝对值的最小值,那么所求得到值便是解答,总的时间复杂度是O(n*logn)。仔细想想

这种方法,很明显,排序减小了我们所需要搜寻的解空间,从而达到了减小时间复杂度的目的。不过这个解

法仍然不能让人满意,因为我们还是浪费时间求出了最终的两个元素,而题目不要求,所以,这肯定不是

最优解。

  三 转化的思想

  再仔细观察题目,我们可以猜到,最优解应该是只求出最小值而不求出具体的元素的,那么该怎么做

呢?我们可能能想到用辅助数组,但是却很难想到怎么做这个辅助。其实这道题我一直在思考如何通过常

规的思维去想到这个最优解,不过我当时没有想出来,而这才是我写这篇博客的原因,即促使我了解

并对这种思路印象深刻,不过这可能只适用于解这题或者类似能让我联想到这种方法的题,这背后更

一般的思维(可以叫做转化,但是还可以更具体些)我还没有想到,希望想到的同学联系我!。

  好了,本题要做的辅助数组是这样一个数组,设它为Bn.原来题目中给定的数组是An,则Bn等于:

  B1 = A1 - A2;

  B2 = A2 - A3;

  B3 = A3 - A4;

  ......

  Bn-1 = An-1 - An.

  注意,Bn的长度是n-1,正好比An要小一个。聪明的同学看到这个辅助数组,立马就能猜到原因了,

因为这样做的话,我们能够把这道看似无从下手求出最优解的问题转化为求Bn的绝对值最小的最长连

续子序列和,因为Bn的连续子序列和便是An任意两数之差(注意,由于题目要求的是绝对值最小,

所以求出A1-A2等效于得出A2-A1),例如:

  A2 - A5 = B2 + B3 + B4 = A2 - A3 + A3 - A4 + A4 - A5 = A2 - A5

  实际上,任何Ai - Aj(i<j) = sigma(k=i -> k=j-1)(k)

  这样的话,我们就成功把问题转化为了连续子序列问题,不过和我们以前做的最大或最小连

续子序列还不完全相同,此处是绝对值最小。那么怎么样的值可能是绝对值最小呢?正数最小或

者负数最大,也就是说在数轴上离0更近的数其绝对值更小,基于此我们可以得到如下的方法。

  和原来求最大连续子序列和一样,要用数学归纳法思考,我们直接看归纳基础,

  归纳基础: 假设已知B1..Bk的绝对值最小连续的连续子序列和是Min(Bk)

  我们利用这个求解B(k+1),加入B(k+1)后有可能比Min(Bk)小的只可能是以B(k+1)结尾的绝对

值最小的连续子序列和,如果把这个和Min(Bk)比较就可以知道是否需要更新Min(Bk)。所以,我

们加强这个归纳基础。

  更强的归纳基础: 假设已知B1..Bk的绝对值最小连续的连续子序列和Min(Bk),以及以

Bk结尾的绝对值最小连续子序列和Suffix(Bk)

  有了这个归纳,我们可以去想如何维护这个Suffix(Bk),目标是使的Suffix(B(k+1))仍然是以

B(k+1)结尾的最小连续子序列和。如果按照求最小和的思路,那便是只要Suffix(Bk)是正数

便置它为0,因为如果它是正数,那么在后续求Suffix(B(k+1))时就肯定比用0要更大,因为

正数会使得整个值变大,而0不会。同样的道理,我们只要使得求Suffix的时候比直接置0

更小即可,否则我们可以直接把Suffix(B(k+1))置0以获得更小值。由于我们求的是绝对

值最小,直接按最小值的思路是不行的,因为可能某个Suffix是暂时求得一个很小的负数,

下次加上某个正数会使得它成为很小的正数,所以不能以正数负数作定论而要以与0的

距离。所以我们应该采取比较符号的方法,如果当前suffix和下一个数的符号相反,那么

可以继续相加以求得下一个suffix,因为我们可以获得绝对值更小的suffix;如果是同号,

无论正负一定会比把当前suffix置0更糟糕,因为这将使得下次的suffix在数轴上离0更远。

所以我们维护Suffix的公式如下: 

  Suffix(B(k+1)) = Suffix(B(k)) + B(k+1), if (Suffix(B(k))*B(k+1)) < 0

  Suffix(B(k+1)) = 0, if (Suffix(B(k))*B(k+1)) ) > 0

  这样我们一直归纳下去,便可以求得最终的Min(Bn),即可求得解。整个的时间复杂

度是O(n),空间复杂度是O(n)。

  四 程序

  程序如下:

[cpp]  view plain copy
  1. #include"stdafx.h"   
  2. #include<iostream>  
  3. #include<cmath>  
  4. usingnamespacestd;   
  5. intGetMinAbsoluteSubsequence(intB[],intnLen)  
  6. {  
  7.     int nGlobal=INT_MAX;  
  8.     int nSuffix=0;  
  9.     for(inti=0; i<nLen; i++)  
  10.     {  
  11.         if(nSuffix*B[i]>0)  
  12.             nSuffix=0;  
  13.         nSuffix+=B[i];   
  14.         if(abs(nSuffix)<abs(nGlobal))  
  15.         {  
  16.             nGlobal=nSuffix;  
  17.         }   
  18.     }  
  19.     returnabs(nGlobal);  
  20. }  
  21. int GetMinAbsoluteDiff(intA[],int nLen)  
  22. {  
  23.     //create aid array  
  24.     int*b=newint[nLen-1];  
  25.     memset(b,0,sizeof(b[0])*(nLen-1));  
  26.     for(inti=0; i<nLen-1; i++)  
  27.     {  
  28.         b[i]=A[i]-A[i+1];  
  29.     }  
  30.     returnGetMinAbsoluteSubsequence(b,nLen-1);  
  31. }  
  32. int_tmain(intargc, _TCHAR*argv[])  
  33. {  
  34.     intA[]={1,20,200,16,13};  
  35.     int nLen=5;  
  36.     cout<<GetMinAbsoluteDiff(A,nLen);  
  37.     getchar();  
  38.     return0;  
  39. }  
五 总结

  整个思路过程便是这样,总的来说,这类题目还是很有思考价值的,至少让我们体会

到了各种美,也能深刻领会转化的意义。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值