Leetcode:No.170 Two Sum III - Data structure design

Design a data structure that accepts a stream of integers and checks if it has a pair of integers that sum up to a particular value.
Implement the TwoSum class:
TwoSum() Initializes the TwoSum object, with an empty array initially.
void add(int number) Adds number to the data structure.
boolean find(int value) Returns true if there exists any pair of numbers whose sum is equal to value, otherwise, it returns false.
Example 1:
Input
["TwoSum", "add", "add", "add", "find", "find"]
[[], [1], [3], [5], [4], [7]]
Output
[null, null, null, null, true, false]
Explanation
TwoSum twoSum = new TwoSum();
twoSum.add(1); // [] --> [1]
twoSum.add(3); // [1] --> [1,3]
twoSum.add(5); // [1,3] --> [1,3,5]
twoSum.find(4); // 1 + 3 = 4, return true
twoSum.find(7); // No two integers sum up to 7, return false
Constraints:
-10^5 <= number <= 10^5
-2^31 <= value <= 2^31 - 1
At most 5 * 10^4 calls will be made to add and find.

TwoSum數據結構版哭廉。初看起來還是很簡單的瑰枫,只要套上TwoSum的解法即可:

import java.util.*;

class TwoSum {

    // number - is duplicate map
    private final Map<Integer, Boolean> map;

    /**
     * Initialize your data structure here.
     */
    public TwoSum() {
        map = new HashMap<>();
    }

    /**
     * Add the number to an internal data structure..
     */
    public void add(int number) {
        if (map.containsKey(number)) {
            map.put(number, true);
        } else {
            map.put(number, false);
        }
    }

    /**
     * Find if there exists any pair of numbers which sum is equal to the value.
     */
    public boolean find(int value) {
        for (int key : map.keySet()) {
            int t = value - key;
            // value = 2*key and we have duplicate
            if (t == key && map.get(t)) return true;
            if (t != key && map.containsKey(t)) return true;
        }
        return false;
    }
}

時間效率上因宇,add是O(1)祥山,find是O(N)忍些,N是此時map中key的數量觉吭。
這種做法能AC,但是就最后的運行時間來看憔古,屬于相對后面的位置遮怜。


image.png

那么前面的都是怎么做的呢?
我參考了前面的做法鸿市,發(fā)現(xiàn)訣竅就是:充分利用題目給出的范圍限制锯梁,然后用Array代替Map即碗。
用Array代替Map,需要注意這些點:

  • Map的key可用Array的index來替代涝桅;
  • Map的value可用Array的value來替代拜姿;
  • Map的遍歷是一個問題,因為假如直接遍歷Array冯遂,效率會低很多蕊肥。需要額外的數據結構來協(xié)助映射。

-10^5 <= number <= 10^5

這一個限制是很有利用價值的蛤肌。因為Array的index不能為負數壁却,我們需要給number加上10^5轉化為自然數。也就是說裸准,開一個[0, 200000]的Array展东,就可囊括所有number。
number已經加了10^5炒俱,它們的和自然就加了2倍這么多盐肃,也就是說和會在[0, 400000]這個區(qū)間了。不過我們可以不用在意這個权悟,畢竟當初的map也沒有牽涉到和砸王。
此外,需要另外維持一個數據結構來直接放number峦阁,這樣就可以不用遍歷整個[0谦铃,200000]了。大小的話榔昔,根據題目限制驹闰,不會超過50000個add。如使用Array需要記錄它的實際大小撒会,不然可用List/Set代替嘹朗。
最后就是一點額外優(yōu)化:動態(tài)記錄存放number的最大最小值,這樣可以先進行一次界限判斷诵肛,即value>2*max||value<2*min時屹培,是肯定無法滿足條件的。
注意我們選擇int Array而不是Boolean曾掂,這是因為惫谤,在map當中key存不存在就是一個信息壁顶,也就是說有不存在珠洗,true和false3種,所以boolean就夠了若专;而這里index已經存在了许蓖,所以boolean是不夠承載3種信息的,要用int。

import java.util.*;

public class TwoSum {

    private final int[] arr;
    private final Set<Integer> nums;
    private int min = 100000;
    private int max = -100000;

    /**
     * Initialize your data structure here.
     */
    public TwoSum() {
        arr = new int[200001];
        nums = new HashSet<>();
    }

    /**
     * Add the number to an internal data structure..
     */
    public void add(int number) {
        if (arr[number + 100000] == 0) {
            nums.add(number);
            min = Math.min(min, number);
            max = Math.max(max, number);
        }
        arr[number + 100000]++;
    }

    /**
     * Find if there exists any pair of numbers which sum is equal to the value.
     */
    public boolean find(int value) {
        if (value > 2 * max || value < 2 * min) return false;
        for (int n : nums) {
            int t = value - n;
            switch (arr[t + 100000]) {
                case 0:
                    break;
                case 1:
                    if (t != n) return true;
                    break;
                default:
                    return true;
            }
        }
        return false;
    }
}

現(xiàn)在運行時間就短多了:


image.png

更進一步膊爪,Set我也不要:

class TwoSum {

    private final int[] arr;
    private final int[] nums;
    int i = 0;
    private int min = 100000;
    private int max = -100000;

    /**
     * Initialize your data structure here.
     */
    public TwoSum() {
        arr = new int[200001];
        nums = new int[50000];
    }

    /**
     * Add the number to an internal data structure..
     */
    public void add(int number) {
        if (arr[number + 100000] == 0) {
            nums[i] = number;
            i++;
            min = Math.min(min, number);
            max = Math.max(max, number);
        }
        arr[number + 100000]++;
    }

    /**
     * Find if there exists any pair of numbers which sum is equal to the value.
     */
    public boolean find(int value) {
        if (value > 2 * max || value < 2 * min) return false;
        for (int j = 0; j < i; j++) {
            int n = nums[j];
            int t = value - n;
            switch (arr[t + 100000]) {
                case 0:
                    break;
                case 1:
                    if (t != n) return true;
                    break;
                default:
                    return true;
            }
        }
        return false;
    }
}

還是有提升的:


image.png

總結:
這道題算法倒是其次自阱,主要還是優(yōu)化有點意思。雖然面試過程中不要求做出這些優(yōu)化米酬,但是提一提還是可以的沛豌。至于實際應用,則要考量是不是性能瓶頸赃额,因為畢竟犧牲了可讀性加派。總而言之跳芳,可以不用芍锦,但最好知道有這么回事。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末飞盆,一起剝皮案震驚了整個濱河市娄琉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌吓歇,老刑警劉巖孽水,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異照瘾,居然都是意外死亡匈棘,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進店門析命,熙熙樓的掌柜王于貴愁眉苦臉地迎上來主卫,“玉大人,你說我怎么就攤上這事鹃愤〈亟粒” “怎么了?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵软吐,是天一觀的道長瘩将。 經常有香客問我,道長凹耙,這世上最難降的妖魔是什么姿现? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮肖抱,結果婚禮上备典,老公的妹妹穿的比我還像新娘。我一直安慰自己意述,他們只是感情好提佣,可當我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布吮蛹。 她就那樣靜靜地躺著,像睡著了一般拌屏。 火紅的嫁衣襯著肌膚如雪潮针。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天倚喂,我揣著相機與錄音每篷,去河邊找鬼。 笑死端圈,一個胖子當著我的面吹牛雳攘,可吹牛的內容都是我干的。 我是一名探鬼主播枫笛,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼吨灭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了刑巧?” 一聲冷哼從身側響起喧兄,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎啊楚,沒想到半個月后吠冤,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡恭理,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年拯辙,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片颜价。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡涯保,死狀恐怖,靈堂內的尸體忽然破棺而出周伦,到底是詐尸還是另有隱情夕春,我是刑警寧澤,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布专挪,位于F島的核電站及志,受9級特大地震影響,放射性物質發(fā)生泄漏寨腔。R本人自食惡果不足惜速侈,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望迫卢。 院中可真熱鬧倚搬,春花似錦、人聲如沸靖避。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽幻捏。三九已至盆犁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間篡九,已是汗流浹背谐岁。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留榛臼,地道東北人伊佃。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像沛善,于是被迫代替她去往敵國和親航揉。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,969評論 2 355