題目:有一個整數數組nums,能否從中取出兩個數,使他們的和爲target。
輸入1:
nums = {4,5,7,10}
target = 12
輸出1:
true
輸入2:
nums = {4,5,7,10}
target = 8
輸出2:
false
題目分析:
首先由給出的輸入輸出案例,可知取出的兩個數不能爲同一個數(不放回取數);其次整數數組nums是否有序是不確定的;最後數組中可能會有相同元素,如若數組nums改爲{4,4,7,10},輸出即爲true。
思路分析1:
首先想到的是暴力法:利用雙指針,其中一個指針固定,另一個指針遍歷數組。時間複雜度O(n*n)。
優化:先將數組進行排序sort,從頭遍歷數組,假設此時遍歷值爲value,再使用二分查找剩餘數組是否存在 (target-value)。時間複雜度O(n*logn)。
代碼實現:
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
bool BeSum(vector<int>& nums, int target)
{
sort(nums.begin(), nums.end()); //對數組排序
for (int i = 0; i < nums.size(); ++i) {
if (nums[i] > target) //如果當前元素大於target,後面元素也必定大於target
break;
bool b = binary_search(nums.begin() + i + 1, nums.end(), target-nums[i]); //對後面元素二分查找
if (b)
return true;
}
return false;
}
int main()
{
vector<int> nums;
int n,t;
cin >> n; //輸入數組元素個數
for(int i = 0; i < n; ++i)
{
cin >> t;
nums.push_back(t);
}
int target;
cin >> target;
if (BeSum(nums, target))
cout << "true" << endl;
else
cout << "false" << endl;
return 0;
}
思路分析2:
若要得到O(n)的時間複雜度,該如何做呢?若使用時間複雜度爲O(1)的哈希查找算法進行查找,便可使整體複雜度降爲O(n)。
(1)首先可想到:將數組全部存入哈希表,再進行掃描和查找,但若nums={4,5,7,10},target=8,輸出爲true,結果錯誤,pass;
(2)若給每個哈希表項加上一個計數值ct,用來存放數值重複次數,較麻煩,不採用;
(3)更簡單的實現:邊掃描邊構建哈希表,逆向考察思路分析1,從最後一個元素開始掃描,並查找該元素之後的元素是否存在target-value,若查找成功,即返回true,否則將該value加入哈希表,再掃描前一個元素。由對稱性可知,從第一個元素開始掃描也具有同樣的效果。
代碼實現:
#include<iostream>
#include<vector>
#include<unordered_set>
using namespace std;
bool BeSum(vector<int>& nums, int target)
{
unordered_set<int> appeared; //構建哈希表(STL中unorder_set使用哈希實現,set使用紅黑樹實現)
for (int i = 0; i < nums.size(); ++i) {
if (appeared.count(target - nums[i]))
return true;
appeared.insert(nums[i]);
}
return false;
}
int main()
{
vector<int> nums;
int n, t;
cin >> n; //輸入數組元素個數
for (int i = 0; i < n; ++i)
{
cin >> t;
nums.push_back(t);
}
int target;
cin >> target;
if (BeSum(nums, target))
cout << "true" << endl;
else
cout << "false" << endl;
return 0;
}
總結:
對於array的題目,可以優先考慮雙針模型。
箴言錄
見賢思齊焉,見不賢而內自省也。