18. 四數(shù)之和

題目鏈接:國際版命浴,國內(nèi)版
公司:Meta
解法:雙指針问窃、遞歸

題目描述

Given an array nums of n integers, return an array of all the unique quadruplets [nums[a], nums[b], nums[c], nums[d]] such that:

  • 0 <= a, b, c, d < n
  • a, b, c, and d are distinct.
  • nums[a] + nums[b] + nums[c] + nums[d] == target

You may return the answer in any order.

Example 1:

Input: nums = [1,0,-1,0,-2,2], target = 0
Output: [[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]

Example 2:

Input: nums = [2,2,2,2,2], target = 8
Output: [[2,2,2,2]]

思路

如果你已經(jīng)做過 2sum3sum 了工禾,那么這道題的題目描述你應(yīng)該已經(jīng)很熟悉了炼蛤,即:在一個無序且有重復(fù)的數(shù)組中找到四個元素莫换,使它們的和為 0伊佃,返回所有可能的結(jié)果』篮粒看到這里蹲坷,我們首先先來回憶一下 3sum 的解法驶乾,即:將數(shù)組排好序,每次固定一個元素 nums[i]冠句,再在剩余的子數(shù)組 nums[i+1:] 中找 2sum 結(jié)果為 target - nums[i] 的兩個元素即可轻掩。那么以此類推,對于這道 4sum懦底,我們也可以將數(shù)組排好序之后固定一個元素唇牧,在剩下的數(shù)組元素中找 3sum。這種思路的參考代碼如下:

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        """ 固定住第一個元素聚唐,對后續(xù)元素進行threeSum丐重,注意去重 """
        def three_sum(nums, start, target):
            def two_sum(numbers, start_idx, target):
                res = []
                i, j = start_idx, len(numbers) - 1
                while i < j:
                    tmp = numbers[i] + numbers[j]
                    left, right = numbers[i], numbers[j]
                    if tmp < target:
                        while i < j and numbers[i] == left: i += 1
                    elif tmp > target:
                        while i < j and numbers[j] == right: j -= 1
                    else:
                        res.append([i, j])
                        while i < j and numbers[i] == left: i += 1
                        while i < j and numbers[j] == right: j -= 1
                return res
            res = [] 
            i = start
            while i < len(nums):
                tuples = two_sum(nums, i + 1, target - nums[i])
                for j, k in tuples:
                    res.append([i, j, k])
                while i < len(nums) - 1 and nums[i + 1] == nums[i]:
                    i += 1
                i += 1
            return res


        nums.sort()
        res = []
        a = 0
        while a < len(nums):
            tuples = three_sum(nums, a + 1, target - nums[a])
            for b, c, d in tuples:
                res.append([nums[a], nums[b], nums[c], nums[d]])
            while a < len(nums) - 1 and nums[a + 1] == nums[a]:
                a += 1
            a += 1
        return res

這種解法可以解題,但存在一個問題杆查,即:如果面試的時候面試官問你 5sum扮惦、6sum 怎么寫,難道我們還能從 2sum 開始一層一層地寫下去么亲桦?為此我們再次觀察一下思路:求 4sum 我們需要知道 3sum崖蜜,求解 3sum 我們需要知道 2sum,求解 2sum 就可以直接在 O(N) 的時間內(nèi)算出來了客峭。因此豫领,求解 nSum 問題,我們需要知道 (n-1)Sum 的解舔琅,這就變成了一個遞歸的解法等恐。同時,遞歸的終止條件是 2sum备蚓。參考代碼如下:

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        """通用解法"""
        def nSum(nums, n, start, target):
            res = []
            if n < 2:
                return res
            if n == 2:
                i, j = start, len(nums) - 1
                while i < j:
                    curr = nums[i] + nums[j]
                    left, right = nums[i], nums[j]
                    if curr < target:
                        # 去重
                        while i < j and nums[i] == left:
                            i += 1
                    elif curr > target:
                        # 去重
                        while i < j and nums[j] == right:
                            j -= 1
                    else:
                        res.append([left, right])
                        # 去重
                        while i < j and nums[i] == left:
                            i += 1
                        while i < j and nums[j] == right:
                            j -= 1
                return res
            else:
                i = start
                while i < len(nums):
                    tmp = nSum(nums, n - 1, i + 1, target - nums[i])
                    for tmp_res in tmp:
                        tmp_res.append(nums[i])
                        res.append(tmp_res)
                    # 去重
                    while i < len(nums) - 1 and nums[i + 1] == nums[i]:
                        i += 1
                    i += 1
            return res
        
        nums.sort()
        return nSum(nums, 4, 0, target)

我們這里定義了一個名為 nSum 的 helper function课蔬,它的作用就是對于給定的數(shù)組,從中找出 n 個數(shù)郊尝,使其和為 target二跋。退出條件如之前所述,是 n == 2 的時候流昏,就演變?yōu)榱?2sum扎即。當 n > 2 的時候,我們每次需要固定一個元素横缔,再在剩下的元素中尋找 (n-1)sum铺遂。對于返回的每一個可能的組合衫哥,我們將其拼裝成最后的結(jié)果茎刚,即在列表中加上所固定的那個元素即可。

對于時間復(fù)雜度分析撤逢,我們需要看遞歸樹的深度膛锭。假設(shè)數(shù)組長度為 N粮坞,我們要求 k sum,由于遞歸退出的條件是 k = 2初狰,因此總的遞歸樹深度應(yīng)該為 k - 1莫杈,時間復(fù)雜度應(yīng)該為 O(N^(k-1))。對于空間復(fù)雜度分析奢入,我們主要考慮遞歸需要的棧的空間筝闹。由于遞歸樹深度為 k -1,因此棧的空間復(fù)雜度應(yīng)該為 O(k-1)腥光,在最壞情況下 k 應(yīng)該等于 n关顷,則空間復(fù)雜度為 O(N)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市武福,隨后出現(xiàn)的幾起案子议双,更是在濱河造成了極大的恐慌,老刑警劉巖捉片,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件平痰,死亡現(xiàn)場離奇詭異,居然都是意外死亡伍纫,警方通過查閱死者的電腦和手機宗雇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來翻斟,“玉大人逾礁,你說我怎么就攤上這事》孟В” “怎么了嘹履?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長债热。 經(jīng)常有香客問我砾嫉,道長,這世上最難降的妖魔是什么窒篱? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任焕刮,我火速辦了婚禮,結(jié)果婚禮上墙杯,老公的妹妹穿的比我還像新娘配并。我一直安慰自己,他們只是感情好高镐,可當我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布溉旋。 她就那樣靜靜地躺著,像睡著了一般嫉髓。 火紅的嫁衣襯著肌膚如雪观腊。 梳的紋絲不亂的頭發(fā)上邑闲,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天,我揣著相機與錄音梧油,去河邊找鬼苫耸。 笑死,一個胖子當著我的面吹牛儡陨,可吹牛的內(nèi)容都是我干的褪子。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼骗村,長吁一口氣:“原來是場噩夢啊……” “哼褐筛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起叙身,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤渔扎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后信轿,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體晃痴,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年财忽,在試婚紗的時候發(fā)現(xiàn)自己被綠了倘核。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡即彪,死狀恐怖紧唱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情隶校,我是刑警寧澤漏益,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站深胳,受9級特大地震影響绰疤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜舞终,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一轻庆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧敛劝,春花似錦余爆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春转捕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背唆垃。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工五芝, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人辕万。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓枢步,卻偏偏與公主長得像,于是被迫代替她去往敵國和親渐尿。 傳聞我的和親對象是個殘疾皇子醉途,可洞房花燭夜當晚...
    茶點故事閱讀 44,700評論 2 354

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