LeetCode 652, 644, 406, 341

LeetCode 652 Find Duplicate Subtrees

鏈接:https://leetcode.com/problems/find-duplicate-subtrees/

方法:遞歸、哈希、樹的編號

時間復雜度:O(n)洒缀,n為樹節(jié)點個數(shù)
想法:參考自花花醬https://www.youtube.com/watch?v=JLK92dbTt8k伦泥。想法是對樹結構進行哈希,使得相同結構的樹,哪怕不是同一棵、地址不一樣,也能對應到相同的值怜珍。這道題的其中一個做法是用二叉樹序列化,但顯然太麻煩凤粗。這里使用的是給二叉樹一個編號id的方法酥泛。每一個樹今豆,都用一個字符串代表(在下面代碼優(yōu)化為long類型數(shù)字),他可以是當前節(jié)點的值 + 左邊的id + ","+ 右邊的id柔袁。這樣遞歸到葉子節(jié)點呆躲,就會導致相同值的葉子節(jié)點,哈希出來的字符串是相同的捶索,那么遞歸一路返回就最后導致相同結構的樹對應的字符串完全相同插掂。還有一個counts的哈希表,是從id映射到個數(shù)腥例,表示能對應到這個id的樹有多少個辅甥。所以說每次發(fā)現(xiàn)ids這個map里面沒有哈希出來的字符串時,就新開一個id燎竖,為ids.size() + 1璃弄。而每次counts里面得到一個值為2的key-value pair的時候,說明有某個id被重復用到了构回,說明以當前的節(jié)點為根的子樹遇上了重復夏块,加入結果中。
另外一個學習點:映射樹結構的時候纤掸,直接搞字符串拼接比較慢脐供,觀察到里面只跟root.val, left id, right id有關,并且題目的數(shù)字數(shù)據(jù)范圍允許茁肠,因此直接把三個值拼接成一個long類型的值患民,這樣查詢比拼接字符串然后查找字符串快多了缩举。
代碼:

class Solution {
    public List<TreeNode> findDuplicateSubtrees(TreeNode root) {
        List<TreeNode> res = new ArrayList<>();
        Map<Long, Integer> ids = new HashMap<>();
        Map<Integer, Integer> counts = new HashMap<>();
        getId(root, res, ids, counts);
        return res;
    }
    
    private int getId(TreeNode root, List<TreeNode> res, Map<Long, Integer> ids, Map<Integer, Integer> counts){
        if (root == null) {
            return 0;
        }
        
        long key = ((long)root.val << 32) | (getId(root.left, res, ids, counts) << 16) | (getId(root.right, res, ids, counts));
        
        int id = 0;
        if (ids.containsKey(key)) {
            id = ids.get(key);
        }
        else {
            id = ids.size() + 1;
            ids.put(key, id);
        }
        
        int tmp = counts.getOrDefault(id, 0) + 1;
        counts.put(id, tmp);
        if (tmp == 2) {
            res.add(root);
        }
        
        return id;
    }
}

LeetCode 644 Maximum Average Subarray II

鏈接:https://leetcode.com/problems/maximum-average-subarray-ii/

方法:二分

時間復雜度:O(nlogL)垦梆,其中n是數(shù)組長度,L是數(shù)組當中值的值域范圍
想法:這個題寫的是hard仅孩,但其實倒也沒有那么難做托猩,它考察了幾個很好的知識點,相當于說是幾個medium的綜合題辽慕,那如果你對這幾個題中的任何一個做的不是很熟練的話可能這題就會GG京腥。首先是想到用二分答案來做。這題的兩個變量是最大平均值v和要求的子數(shù)組最小長度k溅蛉,其中被要求滿足的子數(shù)組最小長度k是自變量公浪,在此要求下的最大平均值v是變量,我們的二分答案是來二分變量船侧。非常直觀的想法是對于子數(shù)組最小長度k的要求越低欠气,能夠達到的子數(shù)組當中的最大平均值就越大。這樣先想清楚了問題的第一部分镜撩。
問題的第二部分:在一個數(shù)組中预柒,給定子數(shù)組的最小長度,怎樣高效地計算有沒有這樣的子數(shù)組,使得平均值大于等于某個值target宜鸯?這里有一個很巧妙的做法憔古,就是我不帶著原數(shù)組和平均值來找麻煩,我先在原數(shù)組里把所有數(shù)減掉target淋袖,這樣就把問題轉化為有沒有長度>=k的子數(shù)組鸿市,和>=0。這個就比剛才的問題簡單多了即碗,這樣我們就扔掉了“平均值”這個麻煩事灸芳,可以專心解決前綴問題。搞兩個算前綴的拜姿,一個叫l(wèi)eftSum烙样,從最左邊開始加,一個叫rightSum蕊肥,在它右邊k個單位處谒获。然后每次都更新一下這倆值,維護leftSum的最小值壁却。所以只要rightSum在任何時候>=了leftSum的最小值批狱,我們就找到了這樣的子數(shù)組,問題就解決了展东。這個方法需要學習掌握赔硫,我記得好像還有哪里用過,但我忘了盐肃,有時間找出那道題來再更新這個地方爪膊。
代碼:

class Solution {
    public double findMaxAverage(int[] nums, int k) {
        double left = -10000.0, right = 10000.0;
        while (left + 1e-5 < right) {
            double mid = (left + right) / 2;
            if (canFind(nums, k, mid)) {
                left = mid;
            }
            else {
                right = mid;
            }
        }
        
        return left;
    }
    
    private boolean canFind(int[] nums, int k, double target) {
        double leftSum = 0, rightSum = 0, minLeftSum = 0;
        for (int i = 0; i < k; i++) {
            rightSum += (nums[i] - target);
        }
        
        for (int i = k; i <= nums.length; i++) {
            if (rightSum >= minLeftSum) {
                return true;
            }
            if (i < nums.length) {
                rightSum += (nums[i] - target);
                leftSum += (nums[i - k] - target);
                minLeftSum = Math.min(minLeftSum, leftSum);
            }
        }
        
        return false;
    }
}

LeetCode 406 Queue Reconstruction by Height

鏈接:https://leetcode.com/problems/queue-reconstruction-by-height/

方法:貪心

時間復雜度:O(n2)
想法:主要是看能不能觀察到吧。每個pair第一個元素是高度砸王,第二個元素是前面有多少人高度>=他推盛。一個非常籠統(tǒng)的想法是谦铃,肯定是個子高的人比較好處理耘成,因為個子高的人前面比他個子高的人比較少,所以相對來說狀態(tài)沒那么復雜驹闰,所以做這道題應該從個子高的開始放瘪菌。然后對于個子一樣的人,第二個元素小的說明他站的更靠前一點嘹朗,所以這樣的也應該先處理师妙。那么根據(jù)上述的方案對原數(shù)組排序。排序之后發(fā)現(xiàn)其實直接把每個元素插入到結果list的對應的index上就完了骡显,這里的index就是每個人的pair的第二個元素疆栏。為什么這樣是對的呢曾掂?因為我們按照之前說的排序,當一個元素放的時候壁顶,后面還沒放的元素沒有比他個子還高的珠洗,當前已經(jīng)在list當中的元素要么是跟他一樣高,要么比他高若专,那這時候许蓖,比方說現(xiàn)在處理的人,pair第二個元素是3调衰,說明前面有三個人>=他的高度膊爪,那就直接插入到list第三個位置就滿足要求了熊镣。
代碼:

class Solution {
    public int[][] reconstructQueue(int[][] people) {
        Arrays.sort(people, (a, b) -> {
            if (a[0] != b[0]) {
                return b[0] - a[0];
            }
            return a[1] - b[1];
        });
        
        List<int[]> lst = new ArrayList<>();
        for (int[] p : people) {
            int index = p[1];
            lst.add(index, p);
        }
        
        int[][] res = new int[lst.size()][2];
        int tt = 0;
        for (int[] p : lst) {
            res[tt++] = p;
        }
        
        return res;
    }
}

LeetCode 341 Flatten Nested List Iterator

鏈接:https://leetcode.com/problems/flatten-nested-list-iterator/

方法1:全展平

想法:我一開始的做法...不知道它要考什么兴使,就直接在constructor里面把NestedInteger全拍扁成Integer放進list了。
代碼:

public class NestedIterator implements Iterator<Integer> {
    
    private List<Integer> lst;
    private int i;
    private int size;

    public NestedIterator(List<NestedInteger> nestedList) {
        this.lst = new ArrayList<>();
        dfs(lst, nestedList);
        this.i = 0;
        this.size = lst.size();
    }
    
    private void dfs(List<Integer> lst, List<NestedInteger> nestedList) {
        for (NestedInteger ni : nestedList) {
            if (ni.isInteger()) {
                lst.add(ni.getInteger());
            }
            else {
                dfs(lst, ni.getList());
            }
        }
    }

    @Override
    public Integer next() {
        return this.lst.get(i++);
    }

    @Override
    public boolean hasNext() {
        return this.i < this.size;
    }
}

方法2:棧

想法:這種想法是倒著把原本的list中的元素入棧夭咬,然后根據(jù)題目當中所說的調用方法趋箩,它每次會先調hasNext()赃额,再調next(),那每次在hasNext()里面把棧頂拍平叫确,保證棧頂元素一定要是Integer跳芳,這樣的話在next里面直接pop出來棧頂?shù)闹导纯伞?br> 代碼:

public class NestedIterator implements Iterator<Integer> {
    
    private Stack<NestedInteger> stack = new Stack<>();

    public NestedIterator(List<NestedInteger> nestedList) {
        for (int i = nestedList.size() - 1; i >= 0; i--) {
            stack.push(nestedList.get(i));
        }
    }

    @Override
    public Integer next() {
        return stack.pop().getInteger();
    }

    @Override
    public boolean hasNext() {
        while (!stack.isEmpty()) {
            NestedInteger head = stack.peek();
            if (head.isInteger()) {
                return true;
            }
            
            stack.pop();
            List<NestedInteger> lst = head.getList();
            for (int i = lst.size() - 1; i >= 0; i--) {
                stack.push(lst.get(i));
            }
        }
        
        return false;
    }
}
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市竹勉,隨后出現(xiàn)的幾起案子飞盆,更是在濱河造成了極大的恐慌,老刑警劉巖次乓,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吓歇,死亡現(xiàn)場離奇詭異,居然都是意外死亡檬输,警方通過查閱死者的電腦和手機照瘾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來丧慈,“玉大人,你說我怎么就攤上這事主卫√幽” “怎么了?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵簇搅,是天一觀的道長完域。 經(jīng)常有香客問我,道長瘩将,這世上最難降的妖魔是什么吟税? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任凹耙,我火速辦了婚禮,結果婚禮上肠仪,老公的妹妹穿的比我還像新娘肖抱。我一直安慰自己,他們只是感情好异旧,可當我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布意述。 她就那樣靜靜地躺著,像睡著了一般吮蛹。 火紅的嫁衣襯著肌膚如雪荤崇。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天潮针,我揣著相機與錄音术荤,去河邊找鬼。 笑死每篷,一個胖子當著我的面吹牛喜每,可吹牛的內容都是我干的。 我是一名探鬼主播雳攘,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼带兜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了吨灭?” 一聲冷哼從身側響起刚照,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎喧兄,沒想到半個月后无畔,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡吠冤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年浑彰,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拯辙。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡郭变,死狀恐怖,靈堂內的尸體忽然破棺而出涯保,到底是詐尸還是另有隱情诉濒,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布夕春,位于F島的核電站未荒,受9級特大地震影響,放射性物質發(fā)生泄漏及志。R本人自食惡果不足惜片排,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一寨腔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧率寡,春花似錦迫卢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至比默,卻和暖如春幻捏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背命咐。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工篡九, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人醋奠。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓榛臼,卻偏偏與公主長得像,于是被迫代替她去往敵國和親窜司。 傳聞我的和親對象是個殘疾皇子沛善,可洞房花燭夜當晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內容