游戲夜讀 | Two Sum問題的八個解

文/良宵聽雨。授權(quán)“游戲夜讀”發(fā)表。

打開LeetCode找到一個小游戲

\1. Two Sum

Easy

Given an array of integers, return indices of the two numbers such that they add up to a specific target.

You may assume that each input would have exactly one solution, and you may not use the same element twice.

Example:

Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

自助使用Python3款答題紙

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:

開始答題……其他略。題目中有兩個假設(shè):

1 有且僅有一個解;

2 同一個元素不能被使用兩次。

嘗試的5種方法阅懦,失敗了4次

        # 方法1:循環(huán)遍歷列表中的數(shù),一個一個找
        # for i in nums:
        #     for j in nums:
        #         if nums.index(i) != nums.index(j):
        #             if (i+j)==target:
        #                 return [nums.index(i), nums.index(j)]
        # 上述方法1有個漏洞:當i=j徘铝,比如遇到[3,3]耳胎,.index()的判斷就不好用了

        
        # 方法2:基于方法1惯吕,循環(huán)遍歷列表的索引,這樣就避免數(shù)值相同的bug啦
        # for i in range(len(nums)):
        #     for j in range(len(nums)):
        #         if i != j:
        #             if nums[i] + nums[j] == target:
        #                 return [i, j]
        # 上述方法2雖然可行怕午,但是Time Limit Exceeded废登,說明效率太低,被淘汰了
        
        
        # 方法3:根據(jù)題目中說的假設(shè)(恰有一個答案)郁惜,直接匹配差值是否在列表中堡距,并對相同值的情況做處理
        # for i in nums:
        #     if (target - i) in nums:
        #         if i == (target - i):
        #             return [nums.index(i), nums.index(i, nums.index(i)+1)]
        #         else:
        #             return [nums.index(i), nums.index(target-i)]
        # 上述方法3有漏洞:相同的值被取了兩次實際卻只有一個,遇到[3,2,4]就歇菜了兆蕉,i=3沒有兩個3返回null
        
                
        # 方法4:基于方法3羽戒,加一個符合條件的數(shù)值數(shù)量的判斷,彌補漏洞
        # for i in nums:
        #     if (target - i) in nums:
        #         if i == (target - i) and nums.count(i) > 1:
        #             return [nums.index(i), nums.index(i, nums.index(i)+1)]
        #         else:
        #             return [nums.index(i), nums.index(target-i)]
        # 上述方法4還是有漏洞虎韵,遇到[3,2,4]沒有歇菜半醉,但是返回了[0,0],判斷條件沒搞清楚邏輯劝术,畫NS圖自救,
        # 發(fā)現(xiàn)是漏掉了i==(target-i) and .count(i)<1 這一類情況呆奕,應(yīng)當continue养晋,而不是直接進上述的else
        
        
        # 方法5:基于方法3和方法4,圍繞不能復(fù)用的條件梁钾,進行兩層判斷:先挖坑绳泉,再網(wǎng)魚,步驟有先后手
        for i in nums:
            if (target - i) in nums:
                if i == (target-i):
                    if nums.count(i) > 1:
                        return [nums.index(i), nums.index(i, nums.index(i)+1)]
                else:
                    return [nums.index(i), nums.index(target-i)]
        # 成功accepted了姆泻!
        # Runtime: 788 ms, faster than 35.47% of Python3 online submissions for Two Sum.
        # Memory Usage: 13.8 MB, less than 70.43% of Python3 online submissions for Two Sum.

上述方法小結(jié)

  1. 總體思路混亂零酪,語無倫次,可悲拇勃。
  2. 冷靜一下四苇,算法的思路主要分兩大類:
    2.1 直接查找計算法(找到一個i和一個j,判斷相應(yīng)和是否為target)方咆;
    2.2 間接查找問詢法(找到一個i月腋,再判斷target與i的差值是否存在)。
  3. 再冷靜一下瓣赂,查找的思路主要分兩大類:
    3.1 基于item
    3.2 基于index

綜上榆骚,在已有的認知范圍內(nèi),理論上有四個方法可以解決LeetCode這個“Two Sum”的問題煌集,分別是:

(1) 基于item的直接查找計算法

        for i in nums:
            for j in nums:
                # find it!
                if (i+j)==target:
                    # maybe twice?
                    if i==j:
                        # more than 1 elements!
                        if nums.count(i)>1:
                            # don't forget find the 2nd one's index
                            return [nums.index(i), nums.index(i, nums.index(i)+1)]
                    # not twice
                    else:        
                        return [nums.index(i), nums.index(j)]

果然凹酥!成功苫纤!
Runtime: 4604 ms, faster than 25.25% of Python3 online submissions for Two Sum.
Memory Usage: 13.8 MB, less than 68.81% of Python3 online submissions for Two Sum.

(2) 基于index的直接查找計算法

        for i in range(len(nums)):
            for j in range(len(nums)):
                if (nums[i]+nums[j])==target:
                    if i==j:
                        if nums.count(nums[i])>1:
                            return [i, nums.index(nums[i], i+1)]
                    else:
                        return [i, j]

果然暗锬啤纲缓!成功!就是慢了點放钦。
Runtime: 7688 ms, faster than 5.01% of Python3 online submissions for Two Sum.
Memory Usage: 13.8 MB, less than 73.03% of Python3 online submissions for Two Sum.

(3) 基于item的間接查找問詢法

        for i in nums:
            if (target-i) in nums:
                if i == (target-i):
                    if nums.count(i)>1:
                        return [nums.index(i), nums.index(i, nums.index(i)+1)]
                else:
                    return [nums.index(i), nums.index(target-i)]

果然吧恰!成功操禀!快了不少褂策。
Runtime: 776 ms, faster than 37.75% of Python3 online submissions for Two Sum.
Memory Usage: 13.8 MB, less than 67.25% of Python3 online submissions for Two Sum.

(4) 基于index的間接查找問詢法

        for i in range(len(nums)):
            if (target - nums[i]) in nums:
                if i==nums.index(target-nums[i]):
                    if nums.count(nums[i])>1:
                        return [i, nums.index(nums[i], i+1)]
                else:
                    return [i, nums.index(target-nums[i])]

果然啊颓屑!成功斤寂!保持在高水準。
Runtime: 788 ms, faster than 35.47% of Python3 online submissions for Two Sum.
Memory Usage: 13.7 MB, less than 85.58% of Python3 online submissions for Two Sum.

做一個回顧

首先恭喜自己揪惦,順利通關(guān)遍搞。分數(shù)還行,Top 65%的位置器腋,770ms溪猿,13.8MB,拿到了一顆星纫塌。

上述的四個方法诊县,不管是“一手抓一手再抓”,還是“一手抓一手在摸”措左,在具體比較的時候都是“憑空”的依痊,沒有放在一個籃子或者秤上進行操作,總而言之就是有不可控的黑洞怎披。

字典dictionary是一個比較喜歡的籃子胸嘁。此外,幾年前看過一個蹺蹺板的方法凉逛,結(jié)合起來:

(5) 基于item的字典dict蹺蹺板

        dict = {}
        for i in nums:
            if i in dict.keys():
                if i == dict.get(i):
                    return [nums.index(i), nums.index(i, nums.index(i)+1)]
                else:
                    # follow the queue number
                    return [nums.index(dict.get(i)), nums.index(i)]
            else:
                dict.update({target-i: i})

厲害了性宏!成功!
Runtime: 36 ms, faster than 94.69% of Python3 online submissions for Two Sum.
Memory Usage: 14.2 MB, less than 50.40% of Python3 online submissions for Two Sum.

(6) 基于index的字典dict蹺蹺板

        dict = {}
        for i in range(len(nums)):
            if nums[i] in dict.keys():
                # ensure index return by the same number
                if i == nums.index(dict.get(nums[i])):
                    return [i, nums.index(dict.get(nums[i]), i+1)]
                else:
                    # follow the queue number
                    return [nums.index(dict.get(nums[i])), i]
            else:
                dict.update({target-nums[i]: nums[i]})

厲害了状飞!不如上面的簡潔衔沼。
Runtime: 40 ms, faster than 87.10% of Python3 online submissions for Two Sum.
Memory Usage: 14.2 MB, less than 53.05% of Python3 online submissions for Two Sum.

對比一下,新的分數(shù)還行昔瞧,Top 5%的位置指蚁,36ms,14.2MB自晰。

寫在最后

最重要的測試集凝化,用例,三個有代表性的列表酬荞,以及目標值:

[2, 7, 11, 15]
9
[3, 3]
6
[3, 2, 4]
6

第二波的對比第一波:排名從前63到了前5搓劫,耗時從776ms到36ms瞧哟,內(nèi)存從13.8MB到14.2MB。

最后的最后枪向,剩下的幾種解法呢勤揩?

簡單來說,就是暴利查找的時候秘蛔,第二層循環(huán)index下標從i+1開始霸赏觥!具體示例如下:

(7) 基于index的直接切片查找法

        for i in nums:
            for j in nums[nums.index(i):]:
                # find it!
                if (i+j)==target:
                    # maybe twice?
                    if i==j:
                        # more than 1 elements!
                        if nums.count(i)>1:
                            # don't forget find the 2nd one's index
                            return [nums.index(i), nums.index(i, nums.index(i)+1)]
                    # not twice
                    else:        
                        return [nums.index(i), nums.index(j)]

成功深员!比原來的速度略有提升负蠕。
Runtime: 3856 ms, faster than 26.13% of Python3 online submissions for Two Sum.
Memory Usage: 13.7 MB, less than 85.58% of Python3 online submissions for Two Sum.

(8) 基于index的間接切片問詢法

        for i in range(len(nums)):
            # begin from i's index + 1, hope more and faster
            if (target - nums[i]) in nums[i+1:]:
                if i==nums.index(target-nums[i]):
                    if nums.count(nums[i])>1:
                        return [i, nums.index(nums[i], i+1)]
                else:
                    return [i, nums.index(target-nums[i])]

成功!但是速度并沒有蹺蹺板的快倦畅。
Runtime: 836 ms, faster than 33.40% of Python3 online submissions for Two Sum.
Memory Usage: 13.8 MB, less than 66.48% of Python3 online submissions for Two Sum.

有幾點需要說明:

  1. 忽略從i+1開始遮糖,是因為直接被[3,3]帶歪思路了,看來用例有時候也是把雙刃劍叠赐。得瑟啥欲账?可悲。
  2. 第一次遇見蹺蹺板的時候芭概,驚為天人赛不,現(xiàn)在沒那么驚嚇了,還是贊嘆谈山。天外有天,山外有山宏怔。
  3. 原本以為加了i+1開始奏路,找的越來越快,能跟蹺蹺板比一比臊诊。發(fā)現(xiàn)還是差了檔次鸽粉,應(yīng)是dict的硬傷。
  4. 雖然說有8個解法抓艳,其實核心思想是這幾個:暴力查找触机、差值問詢、臨時存取玷或、縮減范圍儡首。
  5. 文中引用的數(shù)據(jù)應(yīng)該不精準,看個定性就好偏友。游戲也挺好玩的蔬胯。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市位他,隨后出現(xiàn)的幾起案子氛濒,更是在濱河造成了極大的恐慌产场,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件舞竿,死亡現(xiàn)場離奇詭異京景,居然都是意外死亡,警方通過查閱死者的電腦和手機骗奖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門确徙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人重归,你說我怎么就攤上這事米愿。” “怎么了鼻吮?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵育苟,是天一觀的道長。 經(jīng)常有香客問我椎木,道長违柏,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任香椎,我火速辦了婚禮漱竖,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘畜伐。我一直安慰自己馍惹,他們只是感情好,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布玛界。 她就那樣靜靜地躺著万矾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪慎框。 梳的紋絲不亂的頭發(fā)上良狈,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天,我揣著相機與錄音笨枯,去河邊找鬼薪丁。 笑死,一個胖子當著我的面吹牛馅精,可吹牛的內(nèi)容都是我干的严嗜。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼洲敢,長吁一口氣:“原來是場噩夢啊……” “哼阻问!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起沦疾,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤称近,失蹤者是張志新(化名)和其女友劉穎第队,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體刨秆,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡凳谦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了衡未。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片尸执。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖缓醋,靈堂內(nèi)的尸體忽然破棺而出如失,到底是詐尸還是另有隱情,我是刑警寧澤送粱,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布褪贵,位于F島的核電站,受9級特大地震影響抗俄,放射性物質(zhì)發(fā)生泄漏脆丁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一动雹、第九天 我趴在偏房一處隱蔽的房頂上張望槽卫。 院中可真熱鬧,春花似錦胰蝠、人聲如沸歼培。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽躲庄。三九已至,卻和暖如春翔横,著一層夾襖步出監(jiān)牢的瞬間读跷,已是汗流浹背梗搅。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工禾唁, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人无切。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓荡短,卻偏偏與公主長得像,于是被迫代替她去往敵國和親哆键。 傳聞我的和親對象是個殘疾皇子掘托,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

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