wordpress保存帖子數(shù)據(jù)長沙seo研究中心
題目
給你一個整數(shù)數(shù)組?nums
?,判斷是否存在三元組?[nums[i], nums[j], nums[k]]
?滿足?i != j
、i != k
?且?j != k
?,同時還滿足?nums[i] + nums[j] + nums[k] == 0
?。請你返回所有和為?0
?且不重復(fù)的三元組。
注意:答案中不可以包含重復(fù)的三元組。
示例 1:
輸入:nums = [-1,0,1,2,-1,-4] 輸出:[[-1,-1,2],[-1,0,1]] 解釋: nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。 nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。 nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。 不同的三元組是 [-1,0,1] 和 [-1,-1,2] 。 注意,輸出的順序和三元組的順序并不重要。
示例 2:
輸入:nums = [0,1,1] 輸出:[] 解釋:唯一可能的三元組和不為 0 。
示例 3:
輸入:nums = [0,0,0] 輸出:[[0,0,0]] 解釋:唯一可能的三元組和為 0 。
提示:
3 <= nums.length <= 3000
-105 <= nums[i] <= 105
代碼展示?
class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {vector<vector<int>> result;sort(nums.begin(), nums.end()); // 對數(shù)組進行排序for (int i = 0; i < nums.size() - 2; i++) {if (i > 0 && nums[i] == nums[i - 1]) continue; // 跳過重復(fù)元素int left = i + 1, right = nums.size() - 1;while (left < right) {int sum = nums[i] + nums[left] + nums[right];if (sum < 0) {left++; // 和太小,增加左邊的數(shù)} else if (sum > 0) {right--; // 和太大,減少右邊的數(shù)} else {// 找到一個解result.push_back({nums[i], nums[left], nums[right]});while (left < right && nums[left] == nums[left + 1]) left++; // 跳過重復(fù)的左指針while (left < right && nums[right] == nums[right - 1]) right--; // 跳過重復(fù)的右指針left++;right--;}}}return result;}
};
寫者心得?
對于這一道題目,我剛開始的想法就是用一個循環(huán),再加上一個超長的if循環(huán)解決這個問題??墒莿傄婚_始調(diào)試if循環(huán)的條件就報了錯。在學(xué)習(xí)請教的過程中,我覺得這個代碼有著以下的幾個亮點:
1.在設(shè)定動態(tài)數(shù)組的時候,使用二維數(shù)組。(我剛開始接觸這個題目的時候,我所設(shè)定的數(shù)組并沒有考慮到二維數(shù)組。而題目要求的那個結(jié)果卻是二維數(shù)組,沒有認(rèn)出來,這是我學(xué)識上的不足。)
2.代碼的第二步就對數(shù)組進行了排序(一步的目的其實是為了之后使用雙指針做鋪墊,,但是在我剛開始對于題目思考的時候,也根本沒有考慮到先將元素進行排序之后,更容易得到數(shù)組前后兩個數(shù)的和是否為0)
3.如果在if循環(huán)中條件過多,就應(yīng)該考慮使用while循環(huán)。(他說了我剛開始就是給if循環(huán)里面加了一大堆條件,事實證明這樣的路是走不通的。如果以后遇到了多條件的題目的時候,就應(yīng)該考慮使用while循環(huán),而不是在if循環(huán)里不斷套用。)
4.雙指針,它的精髓在于在數(shù)組中找三個數(shù)和為零的數(shù)字(我在之前的編程中其實使用過雙指針,但是那時候我看的不太懂?,F(xiàn)在我可以總結(jié)出雙指針使用的情況,應(yīng)該就在于與前后兩個數(shù)有關(guān)系的時候,雙指針能發(fā)揮很大的作用。)
5.跳過重復(fù)元素。(這一步看似平平無奇,但其實是使用雙指針至關(guān)重要的前提,試想一下,如果遇到重復(fù)的元素,其輸出的結(jié)果會對于我們對于整個代碼的邏輯產(chǎn)生非常嚴(yán)重的影響。而且,這樣的困擾會一直伴隨著我們對于代碼的讀寫和思考)
6.去重(這一點是我根本就沒有想到的,或者說我的思路還沒有到這一步,但是代碼用了兩個while循環(huán),輕松解決了在得到目標(biāo)數(shù)組之后,如果在二維數(shù)組中這個數(shù)組與其他的數(shù)組重復(fù)的時候的問題。)
?
代碼解釋?
定義和初始化
vector<vector<int>> result;
這行代碼創(chuàng)建了一個空的二維向量 result
。每個內(nèi)部的 vector<int>
將會保存一個三元組。
添加元素
當(dāng)你找到一個滿足條件的三元組時,你可以將其添加到 result
中:
result.push_back({nums[i], nums[left], nums[right]});
這里的 {nums[i], nums[left], nums[right]}
是一個初始化列表,它會被轉(zhuǎn)換成一個 vector<int>
并添加到 result
的末尾。
sort(nums.begin(), nums.end()); // 對數(shù)組進行排序
使用 sort
函數(shù)對輸入數(shù)組 nums
進行升序排序。排序后,可以通過雙指針法有效地查找滿足條件的三元組。
for (int i = 0; i < nums.size() - 2; i++) {
開始一個外層循環(huán),遍歷數(shù)組中的每一個元素,作為第一個數(shù) nums[i]
。這里 i
的范圍是從 0
到 nums.size() - 3
,因為還需要兩個額外的位置來放置另外兩個數(shù)。
if (i > 0 && nums[i] == nums[i - 1]) continue; // 跳過重復(fù)元素
如果當(dāng)前元素 nums[i]
與前一個元素相同,則跳過本次循環(huán),避免產(chǎn)生重復(fù)的三元組。
int left = i + 1, right = nums.size() - 1;
初始化兩個指針 left
和 right
,分別指向當(dāng)前元素 nums[i]
后的第一個位置和數(shù)組的最后一個位置。
while (left < right) {
進入一個內(nèi)層循環(huán),當(dāng) left
指針小于 right
指針時繼續(xù)循環(huán)。
int sum = nums[i] + nums[left] + nums[right];
計算當(dāng)前三個指針?biāo)赶虻脑刂?sum
。
if (sum < 0) {left++; // 和太小,增加左邊的數(shù)
如果 sum
小于零,說明當(dāng)前和太小,需要增大 left
指針?biāo)赶虻臄?shù),因此將 left
向右移動一位。
} else if (sum > 0) {right--; // 和太大,減少右邊的數(shù)
如果 sum
大于零,說明當(dāng)前和太大,需要減小 right
指針?biāo)赶虻臄?shù),因此將 right
向左移動一位。
} else {// 找到一個解result.push_back({nums[i], nums[left], nums[right]});
如果 sum
等于零,說明找到了一個滿足條件的三元組,將其添加到結(jié)果列表 result
中。
while (left < right && nums[left] == nums[left + 1]) left++; // 跳過重復(fù)的左指針
為了避免產(chǎn)生重復(fù)的三元組,如果 left
指針?biāo)赶虻臄?shù)與下一個數(shù)相同,則繼續(xù)將 left
向右移動。
while (left < right && nums[right] == nums[right - 1]) right--; // 跳過重復(fù)的右指針
同理,如果 right
指針?biāo)赶虻臄?shù)與前一個數(shù)相同,則繼續(xù)將 right
向左移動。
left++;
right--;
無論是否有重復(fù)的數(shù),都需要將 left
和 right
指針各向中間移動一位,以便繼續(xù)查找新的可能的三元組。
return result;
返回結(jié)果列表 result
,其中包含了所有滿足條件的三元組。
?