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 要復雜一些,博主考慮過先 fix 一個數(shù),然后另外兩個數(shù)使用 Two Sum 那種 HashMap 的解法,但是會有重復結(jié)果出現(xiàn),就算使用 TreeSet 來去除重復也不行,會 TLE,看來此題并不是考 Two Sum 的解法。來分析一下這道題的特點,要找出三個數(shù)且和為0,那么除了三個數(shù)全是0的情況之外,肯定會有負數(shù)和正數(shù),還是要先 fix 一個數(shù),然后去找另外兩個數(shù),只要找到兩個數(shù)且和為第一個 fix 數(shù)的相反數(shù)就行了,既然另外兩個數(shù)不能使用 Two Sum 的那種解法來找,如何能更有效的定位呢?我們肯定不希望遍歷所有兩個數(shù)的組合吧,所以如果數(shù)組是有序的,那么就可以用雙指針以線性時間復雜度來遍歷所有滿足題意的兩個數(shù)組合。
對原數(shù)組進行排序,然后開始遍歷排序后的數(shù)組,這里注意不是遍歷到最后一個停止,而是到倒數(shù)第三個就可以了。這里可以先做個剪枝優(yōu)化,就是當遍歷到正數(shù)的時候就 break,為啥呢,因為數(shù)組現(xiàn)在是有序的了,如果第一個要 fix 的數(shù)就是正數(shù)了,則后面的數(shù)字就都是正數(shù),就永遠不會出現(xiàn)和為0的情況了。然后還要加上重復就跳過的處理,處理方法是從第二個數(shù)開始,如果和前面的數(shù)字相等,就跳過,因為不想把相同的數(shù)字fix兩次。對于遍歷到的數(shù),用0減去這個 fix 的數(shù)得到一個 target,然后只需要再之后找到兩個數(shù)之和等于 target 即可。用兩個指針分別指向 fix 數(shù)字之后開始的數(shù)組首尾兩個數(shù),如果兩個數(shù)和正好為 target,則將這兩個數(shù)和 fix 的數(shù)一起存入結(jié)果中。然后就是跳過重復數(shù)字的步驟了,兩個指針都需要檢測重復數(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 的不能包含重復項的特點來防止重復項的產(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());
}
};
到此這篇關于python實現(xiàn)LeetCode(三數(shù)之和)的文章就介紹到這了,更多相關python實現(xiàn)三數(shù)之和內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C++中將Char轉(zhuǎn)換成String的4種方法
本文主要介紹了C++中將Char轉(zhuǎn)換成String的4種方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-03-03
C++ 關于 CMFCPropertyGridCtrl 的使用方法
這篇文章主要介紹了C++ 關于 CMFCPropertyGridCtrl 的使用方法的相關資料,需要的朋友可以參考下2015-06-06

