力扣.15 三數(shù)之和 three-sum

數(shù)組系列

力扣數(shù)據(jù)結(jié)構(gòu)之?dāng)?shù)組-00-概覽

力扣.53 最大子數(shù)組和 maximum-subarray

力扣.128 最長(zhǎng)連續(xù)序列 longest-consecutive-sequence

力扣.1 兩數(shù)之和 N 種解法 two-sum

力扣.167 兩數(shù)之和 II two-sum-ii

力扣.170 兩數(shù)之和 III two-sum-iii

力扣.653 兩數(shù)之和 IV two-sum-IV

力扣.015 三數(shù)之和 three-sum

力扣.016 最接近的三數(shù)之和 three-sum-closest

力扣.259 較小的三數(shù)之和 three-sum-smaller

題目

給你一個(gè)整數(shù)數(shù)組 nums 配乱,判斷是否存在三元組 [nums[i], nums[j], nums[k]] 滿足 i != j堪滨、i != k 且 j != k 雷酪,同時(shí)還滿足 nums[i] + nums[j] + nums[k] == 0 。

請(qǐng)你返回所有和為 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

-10^5 <= nums[i] <= 10^5

前言

這道題作為 leetcode 的第 15 道題战秋,看起來(lái)似曾相識(shí)。

大概思路可以有下面幾種:

  1. 暴力解法

  2. 數(shù)組排序+二分

  3. Hash 優(yōu)化

  4. 雙指針

v1-暴力解法

思路

直接 3 次循環(huán)讨韭,找到符合結(jié)果的數(shù)據(jù)返回脂信。

這種最容易想到,一般工作中也是我們用到最多的透硝。

當(dāng)然也必定超時(shí)狰闪。

實(shí)現(xiàn)

class Solution {
   
   public List<List<Integer>> threeSum(int[] nums) {
        Set<List<Integer>> res = new HashSet<>();

        final int n = nums.length;
        for(int i = 0; i < n; i++){
            for(int j = i+1; j < n; j++) {
                for(int k = j+1; k < n; k++) {
                    if(nums[i]+nums[j]+nums[k] == 0) {
                        List<Integer> list = Arrays.asList(nums[i], nums[j], nums[k]);
                        Collections.sort(list);
                        res.add(list);
                    }
                }
            }
        }

        return new ArrayList<>(res);
    }

}

效果

超出時(shí)間限制

308 / 313 個(gè)通過(guò)的測(cè)試用例

小結(jié)

這里慢在幾個(gè)地方:

1)三層循環(huán),找到符合的數(shù)據(jù)

2)數(shù)據(jù)需要去重蹬铺,所以用到了排序尝哆,雖然是一個(gè)小排序。

v2-思維的轉(zhuǎn)換

思路

我們把問(wèn)題這么考慮

要找的數(shù)其實(shí)是:nums[i] + nums[j] + nums[k] == 0

那么甜攀,我們?nèi)绻潭ㄒ粋€(gè)值:

那么問(wèn)題就變成了

nums[j] + nums[k] == -nums[i]

也就是變成了我們的 T001/T167 的題目秋泄。

疑問(wèn) 數(shù)據(jù)去重問(wèn)題呢琐馆?

暫時(shí)先不考慮,過(guò)會(huì)根據(jù)測(cè)試用例優(yōu)化

編程思路

我們定義兩個(gè)指針

left=0
right=n-1
sum=num[left]+num[right-1]

因?yàn)閿?shù)組有有序的恒序,所以只有 3 種情況:

  1. sum == target 直接滿足

  2. sum < target瘦麸,left++

  3. sum > target, right--

實(shí)現(xiàn)

class Solution {
   
   public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);

        Set<List<Integer>> res = new HashSet<>();

        final int n = nums.length;
        // 因?yàn)槭怯行虻模瑥那懊嬲?個(gè)數(shù)字歧胁,等于當(dāng)前數(shù)字更加合理滋饲。
        // nums[j] + nums[k] == -nums[i]

        for(int i = 0; i < n; i++){
            int target = -nums[i];

            int left = 0;
            int right = n-1;

            // 找兩個(gè)數(shù)
            while (left < right) {
                int sum = nums[left]+nums[right];
                if(sum == target) {
                    // 排序+去重
                    if(i != left && left != right && i != right) {
                        List<Integer> list = Arrays.asList(nums[left], nums[right], nums[i]);
                        Collections.sort(list);
                        res.add(list);
                    }
                }
                if(sum < target) {
                    left++;
                } else {
                    right--;
                }
            }
        }

        return new ArrayList<>(res);
    }

}

效果

超出時(shí)間限制 312 / 313 個(gè)通過(guò)的測(cè)試用例

小結(jié)

最大的問(wèn)題還是我們?yōu)槭裁匆ブ兀繛槭裁催@么麻煩

v3-去重

思路

數(shù)據(jù)重復(fù)存在兩個(gè)問(wèn)題:

1)[0, 1, -1] 和 [1, 0, -1] 認(rèn)為重復(fù)

所以我們?cè)诠潭ǖ谝粋€(gè)元素的時(shí)候喊巍,直接跳過(guò) nums[i] == nums[i-1]屠缭,可以解決初始值重復(fù)的問(wèn)題。

2)數(shù)組排序后存在重復(fù)的數(shù)據(jù)崭参,那么我們只需要跳過(guò)重復(fù)的元素即可

我們的 left right 指針移動(dòng)的時(shí)候呵曹,也需要跳過(guò)重復(fù)

初始值的問(wèn)題

我們固定第一個(gè)數(shù) num[i],下標(biāo)從 0, 1, ..., n-3

剩下的兩個(gè)數(shù):從 i+1, ..., n-1 中選擇

代碼

public List<List<Integer>> threeSum(int[] nums) {
    Arrays.sort(nums);
    List<List<Integer>> res = new ArrayList<>();
    final int n = nums.length;
    for(int i = 0; i < n-2; i++){
        // 跳過(guò)重復(fù)的第一個(gè)數(shù)
        if(i > 0 && nums[i] == nums[i-1]) {
            continue;
        }

        // 目標(biāo)值
        int left = i+1;
        int right = n-1;

        // 雙指針
        while (left < right) {
            int sum = nums[i] + nums[left]+nums[right];
            if(sum == 0) {
                List<Integer> list = Arrays.asList(nums[i], nums[left], nums[right]);
                res.add(list);
                // 左右避免數(shù)據(jù)重復(fù)
                while (left < right && nums[left] == nums[left+1]) {
                    left++;
                }
                while (left < right && nums[right] == nums[right-1]) {
                    right--;
                }
            }
            if(sum < 0) {
                left++;
            } else {
                right--;
            }
        }
    }
    return res;
}

效果

32ms 62.27%

效果還行何暮⊙傥梗看了下基本實(shí)現(xiàn)就是這個(gè)。

小結(jié)

這里對(duì)雙指針的理解要求比較高海洼。

而且對(duì)于重復(fù)性數(shù)據(jù)的判斷技巧要求特別高跨新,算得上是一道很接近困難的題目

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市坏逢,隨后出現(xiàn)的幾起案子域帐,更是在濱河造成了極大的恐慌,老刑警劉巖词疼,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件俯树,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡贰盗,警方通過(guò)查閱死者的電腦和手機(jī)许饿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)舵盈,“玉大人陋率,你說(shuō)我怎么就攤上這事』嗤恚” “怎么了瓦糟?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)赴蝇。 經(jīng)常有香客問(wèn)我菩浙,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任劲蜻,我火速辦了婚禮陆淀,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘先嬉。我一直安慰自己轧苫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布疫蔓。 她就那樣靜靜地躺著含懊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪衅胀。 梳的紋絲不亂的頭發(fā)上岔乔,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音拗小,去河邊找鬼重罪。 笑死樱哼,一個(gè)胖子當(dāng)著我的面吹牛哀九,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播搅幅,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼阅束,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了茄唐?” 一聲冷哼從身側(cè)響起息裸,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎沪编,沒(méi)想到半個(gè)月后呼盆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蚁廓,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年访圃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片相嵌。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡腿时,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出饭宾,到底是詐尸還是另有隱情批糟,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布看铆,位于F島的核電站徽鼎,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜否淤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一满败、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧叹括,春花似錦算墨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至侠讯,卻和暖如春挖藏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背厢漩。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工膜眠, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人溜嗜。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓宵膨,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親炸宵。 傳聞我的和親對(duì)象是個(gè)殘疾皇子辟躏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容