日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

程序员面试题精选100题(61)-数对之差的最大值[算法]

發(fā)布時間:2025/3/21 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 程序员面试题精选100题(61)-数对之差的最大值[算法] 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

題目:在數(shù)組中,數(shù)字減去它右邊的數(shù)字得到一個數(shù)對之差。求所有數(shù)對之差的最大值。例如在數(shù)組{2, 4, 1, 16, 7, 5, 11, 9}中,數(shù)對之差的最大值是11,是16減去5的結(jié)果。

分析:看到這個題目,很多人的第一反應(yīng)是找到這個數(shù)組的最大值和最小值,然后覺得最大值減去最小值就是最終的結(jié)果。這種思路忽略了題目中很重要的一點:數(shù)對之差是一個數(shù)字減去它右邊的數(shù)字。由于我們無法保證最大值一定位于數(shù)組的左邊,因此這個思路不管用。

于是我們接下來可以想到讓每一個數(shù)字逐個減去它右邊的所有數(shù)字,并通過比較得到數(shù)對之差的最大值。由于每個數(shù)字需要和它后面的O(n)個數(shù)字作減法,因此總的時間復(fù)雜度是O(n2)

解法一:分治法

通常蠻力法不會是最好的解法,我們想辦法減少減法的次數(shù)。假設(shè)我們把數(shù)組分成兩個子數(shù)組,我們其實沒有必要拿左邊的子數(shù)組中較小的數(shù)字去和右邊的子數(shù)組中較大的數(shù)字作減法。我們可以想象,數(shù)對之差的最大值只有可能是下面三種情況之一:(1)被減數(shù)和減數(shù)都在第一個子數(shù)組中,即第一個子數(shù)組中的數(shù)對之差的最大值;(2)被減數(shù)和減數(shù)都在第二個子數(shù)組中,即第二個子數(shù)組中數(shù)對之差的最大值;(3)被減數(shù)在第一個子數(shù)組中,是第一個子數(shù)組的最大值。減數(shù)在第二個子數(shù)組中,是第二個子數(shù)組的最小值。這三個差值的最大者就是整個數(shù)組中數(shù)對之差的最大值。

在前面提到的三種情況中,得到第一個子數(shù)組的最大值和第二子數(shù)組的最小值不是一件難事,但如何得到兩個子數(shù)組中的數(shù)對之差的最大值?這其實是原始問題的子問題,我們可以遞歸地解決。下面是這種思路的參考代碼:

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); }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; }

在函數(shù)MaxDiffCore中,我們先得到第一個子數(shù)組中的最大的數(shù)對之差leftDiff,再得到第二個子數(shù)組中的最大數(shù)對之差rightDiff。接下來用第一個子數(shù)組的最大值減去第二個子數(shù)組的最小值得到crossDiff。這三者的最大值就是整個數(shù)組的最大數(shù)對之差。

解法二:轉(zhuǎn)化成求解子數(shù)組的最大和問題

接下來再介紹一種比較巧妙的解法。如果輸入一個長度為n的數(shù)組numbers,我們先構(gòu)建一個長度為n-1的輔助數(shù)組diff,并且diff[i]等于numbers[i]-numbers[i+1]0<=i<n-1)。如果我們從數(shù)組diff中的第i個數(shù)字一直累加到第j個數(shù)字(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]

分析到這里,我們發(fā)現(xiàn)原始數(shù)組中最大的數(shù)對之差(即numbers[i] – numbers[j + 1])其實是輔助數(shù)組diff中最大的連續(xù)子數(shù)組之和。我們在本系列的博客的第3《求子數(shù)組的最大和》中已經(jīng)詳細討論過這個問題的解決方法。基于這個思路,我們可以寫出如下代碼:

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];elsecurrentSum += diff[i];if(currentSum > greatestSum)greatestSum = currentSum;}delete[] diff;return greatestSum; }

解法三:動態(tài)規(guī)劃法

既然我們可以把求最大的數(shù)對之差轉(zhuǎn)換成求子數(shù)組的最大和,而子數(shù)組的最大和可以通過動態(tài)規(guī)劃求解,那我們是不是可以通過動態(tài)規(guī)劃直接求解呢?下面我們試著用動態(tài)規(guī)劃法直接求數(shù)對之差的最大值。

我們定義diff[i]是以數(shù)組中第i個數(shù)字為減數(shù)的所有數(shù)對之差的最大值。也就是說對于任意hh < i),diff[i]≥number[h]-number[i]diff[i]0≤i<n)的最大值就是整個數(shù)組最大的數(shù)對之差。

假設(shè)我們已經(jīng)求得了diff[i],我們該怎么求得diff[i+1]呢?對于diff[i],肯定存在一個hh < i),滿足number[h]減去number[i]之差是最大的,也就是number[h]應(yīng)該是number[i]之前的所有數(shù)字的最大值。當(dāng)我們求diff[i+1]的時候,我們需要找到第i+1個數(shù)字之前的最大值。第i+1個數(shù)字之前的最大值有兩種可能:這個最大值可能是第i個數(shù)字之前的最大值,也有可能這個最大值就是第i個數(shù)字。第i+1個數(shù)字之前的最大值肯定是這兩者的較大者。我們只要拿第i+1個數(shù)字之前的最大值減去number[i+1],就得到了diff[i+1]

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; }

在上述代碼中,max表示第i個數(shù)字之前的最大值,而currentDiff表示diff[i]?0≤i<n),diff[i]的最大值就是代碼中maxDiff

解法小結(jié)

上述三種代碼,雖然思路各不相同,但時間復(fù)雜度都是O(n)(第一種解法的時間復(fù)雜度可以用遞歸公式表示為T(n)=2(n/2)+O(1),所以總體時間復(fù)雜度是O(n))。我們也可以注意到第一種方法是基于遞歸實現(xiàn),而遞歸調(diào)用是有額外的時間、空間消耗的(比如在調(diào)用棧上分配空間保存參數(shù)、臨時變量等)。第二種方法需要一個長度為n-1的輔助數(shù)組,因此其空間復(fù)雜度是O(n)。第三種方法則沒有額外的時間、空間開銷,并且它的代碼是最簡潔的,因此這是最值得推薦的一種解法。

?

博主何海濤對本博客文章享有著作權(quán)。網(wǎng)絡(luò)轉(zhuǎn)載請注明出處

http://zhedahht.blog.163.com/。整理出版物請和作者聯(lián)系。對解題思路有任何建議,歡迎在評論中告知,或者加我微博 http://weibo.com/zhedahht或者 http://t.163.com/zhedahht與我討論。謝謝。

總結(jié)

以上是生活随笔為你收集整理的程序员面试题精选100题(61)-数对之差的最大值[算法]的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。