C++實現(xiàn)LeetCode(15.三數(shù)之和)
[LeetCode] 15. 3Sum 三數(shù)之和
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note:
- Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
- The solution set must not contain duplicate triplets.
For example, given array S = {-1 0 1 2 -1 -4},
A solution set is:
(-1, 0, 1)
(-1, -1, 2)
這道題讓我們求三數(shù)之和,比之前那道 Two Sum 要復(fù)雜一些,博主考慮過先 fix 一個數(shù),然后另外兩個數(shù)使用 Two Sum 那種 HashMap 的解法,但是會有重復(fù)結(jié)果出現(xiàn),就算使用 TreeSet 來去除重復(fù)也不行,會 TLE,看來此題并不是考 Two Sum 的解法。來分析一下這道題的特點,要找出三個數(shù)且和為0,那么除了三個數(shù)全是0的情況之外,肯定會有負數(shù)和正數(shù),還是要先 fix 一個數(shù),然后去找另外兩個數(shù),只要找到兩個數(shù)且和為第一個 fix 數(shù)的相反數(shù)就行了,既然另外兩個數(shù)不能使用 Two Sum 的那種解法來找,如何能更有效的定位呢?我們肯定不希望遍歷所有兩個數(shù)的組合吧,所以如果數(shù)組是有序的,那么就可以用雙指針以線性時間復(fù)雜度來遍歷所有滿足題意的兩個數(shù)組合。
對原數(shù)組進行排序,然后開始遍歷排序后的數(shù)組,這里注意不是遍歷到最后一個停止,而是到倒數(shù)第三個就可以了。這里可以先做個剪枝優(yōu)化,就是當遍歷到正數(shù)的時候就 break,為啥呢,因為數(shù)組現(xiàn)在是有序的了,如果第一個要 fix 的數(shù)就是正數(shù)了,則后面的數(shù)字就都是正數(shù),就永遠不會出現(xiàn)和為0的情況了。然后還要加上重復(fù)就跳過的處理,處理方法是從第二個數(shù)開始,如果和前面的數(shù)字相等,就跳過,因為不想把相同的數(shù)字fix兩次。對于遍歷到的數(shù),用0減去這個 fix 的數(shù)得到一個 target,然后只需要再之后找到兩個數(shù)之和等于 target 即可。用兩個指針分別指向 fix 數(shù)字之后開始的數(shù)組首尾兩個數(shù),如果兩個數(shù)和正好為 target,則將這兩個數(shù)和 fix 的數(shù)一起存入結(jié)果中。然后就是跳過重復(fù)數(shù)字的步驟了,兩個指針都需要檢測重復(fù)數(shù)字。如果兩數(shù)之和小于 target,則將左邊那個指針i右移一位,使得指向的數(shù)字增大一些。同理,如果兩數(shù)之和大于 target,則將右邊那個指針j左移一位,使得指向的數(shù)字減小一些,代碼如下:
解法一:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
sort(nums.begin(), nums.end());
if (nums.empty() || nums.back() < 0 || nums.front() > 0) return {};
for (int k = 0; k < (int)nums.size() - 2; ++k) {
if (nums[k] > 0) break;
if (k > 0 && nums[k] == nums[k - 1]) continue;
int target = 0 - nums[k], i = k + 1, j = (int)nums.size() - 1;
while (i < j) {
if (nums[i] + nums[j] == target) {
res.push_back({nums[k], nums[i], nums[j]});
while (i < j && nums[i] == nums[i + 1]) ++i;
while (i < j && nums[j] == nums[j - 1]) --j;
++i; --j;
} else if (nums[i] + nums[j] < target) ++i;
else --j;
}
}
return res;
}
};
或者我們也可以利用 TreeSet 的不能包含重復(fù)項的特點來防止重復(fù)項的產(chǎn)生,那么就不需要檢測數(shù)字是否被 fix 過兩次,不過個人覺得還是前面那種解法更好一些,參見代碼如下:
解法二:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
set<vector<int>> res;
sort(nums.begin(), nums.end());
if (nums.empty() || nums.back() < 0 || nums.front() > 0) return {};
for (int k = 0; k < (int)nums.size() - 2; ++k) {
if (nums[k] > 0) break;
int target = 0 - nums[k], i = k + 1, j = (int)nums.size() - 1;
while (i < j) {
if (nums[i] + nums[j] == target) {
res.insert({nums[k], nums[i], nums[j]});
while (i < j && nums[i] == nums[i + 1]) ++i;
while (i < j && nums[j] == nums[j - 1]) --j;
++i; --j;
} else if (nums[i] + nums[j] < target) ++i;
else --j;
}
}
return vector<vector<int>>(res.begin(), res.end());
}
};
到此這篇關(guān)于python實現(xiàn)LeetCode(三數(shù)之和)的文章就介紹到這了,更多相關(guān)python實現(xiàn)三數(shù)之和內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
QT?UDP網(wǎng)絡(luò)編程實現(xiàn)簡單消息傳輸
這篇文章主要為大家詳細介紹了QT?UDP網(wǎng)絡(luò)編程實現(xiàn)簡單消息傳輸,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-08-08
一文帶你學(xué)習(xí)C/C++中的<Windows.h>庫
c語言 #include<windows.h>是寫window程序需要的重要頭文件,下面這篇文章主要給大家介紹了C/C++中<Windows.h>庫的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2023-01-01
Qt音視頻開發(fā)之實現(xiàn)ffmpeg視頻旋轉(zhuǎn)顯示
這篇文章主要為大家詳細介紹了在Qt音視頻開發(fā)中如何利用ffmpeg實現(xiàn)視頻旋轉(zhuǎn)顯示,文中的實現(xiàn)步驟講講清晰,感興趣的小伙伴可以了解一下2023-03-03
C語言 動態(tài)內(nèi)存開辟常見問題解決與分析流程
動態(tài)內(nèi)存是相對靜態(tài)內(nèi)存而言的。所謂動態(tài)和靜態(tài)就是指內(nèi)存的分配方式。動態(tài)內(nèi)存是指在堆上分配的內(nèi)存,而靜態(tài)內(nèi)存是指在棧上分配的內(nèi)存2022-03-03
使用kendynet構(gòu)建異步redis訪問服務(wù)
這篇文章主要介紹了在kendynet上寫的一個簡單的redis異步訪問接口,大家參考使用吧2014-01-01

