Q:輸入一個遞增排序的數組和一個數字S,在數組中查找兩個數,是的他們的和正好是S,如果有多對數字的和等於S,輸出兩個數的乘積最小的。
思路:
1,因爲數組滿足遞增,從首尾開始遍歷 i,j,如果ai+aj=S,就是答案 (相差越大,乘積越小,所以第一個遇到就是乘積最小的)
2,如果 ai+aj>S, aj肯定不是答案之一,j-- (aj後面的不可能,和只會更大)
3,如果 ai+aj<S, ai肯定不是答案之一,i++ (ai前面的不可能,和只會更小)
複雜度O(n)
題目關鍵在於證明:和爲定值的兩個數,相差越遠乘積越小。
首先是圖形解釋(只適用於 S>0)
下面做數學上的證明:
所取的兩個數分別爲 x 和 S-x
那麼乘積可表示爲:
兩個數的差 , 用y表示x得到
進一步乘積可以表示爲:
顯然,乘積 f 是隨 y單調遞減的,即可證明再實數範圍內,和爲定值的兩個數 差越大,他們的乘積則越小。
簡單的一個demo如下:
#include "stdafx.h"
#include<vector>
#include<iostream>
using namespace std;
vector<int> findMinmul4Sum(vector<int> &arr, int sum)
{
vector<int> result;
int n = arr.size();
int i = 0, j = n - 1;
while (i < j)
{
if (arr[i] + arr[j] == sum) { result.push_back(arr[i]);result.push_back(arr[j]);break; }
if (arr[i] + arr[j] < sum) i++;
if (arr[i] + arr[j] > sum) j--;
}
return result;
}
int main()
{
vector<int> a = {1,2,3,4,5,6,7,8,9};
vector<int> b= findMinmul4Sum(a, 8);
cout << b[0] <<"\t"<<b[1] << endl;
system("pause");
return 0;
}
循環部分可以進一步優化爲
while(i<j)
{
if(arr[i]+arr[j]==sum) ...
while(arr[i]+arr[j]<sum && i<j) i++; //i<j必須
while(arr[i]+arr[j]>sum && i<j) j--;
}
速度可以進一步加快