leetCode進階算法題+解析(二十二)

二叉樹的前序遍歷

題目:給定一個二叉樹,返回它的 前序 遍歷。
題目截圖

思路:這個題也沒啥思路可說的,一個遞歸一個迭代,我都寫一遍就行了。然后之前做過一個中序排列。剛剛還看到下一道題是后續排列。一起做了得了,我去寫代碼了。
首先是遞歸實現:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    List<Integer> res;
    public List<Integer> preorderTraversal(TreeNode root) {
        res = new ArrayList<Integer>();
        pre(root);
        return res;
    }
    public void pre(TreeNode root){
        if(root==null) return;
        res.add(root.val);
        pre(root.left);
        pre(root.right);
    }
}

迭代實現:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {

    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        if(root == null) return res;
        Stack<TreeNode> stack = new Stack<TreeNode>();
        stack.push(root);
        while(root!=null || !stack.isEmpty()){
            if(root!=null){
                res.add(root.val);
                if(root.left != null)stack.push(root.left);
                root = root.left;
            }else{                
                root =  stack.pop();                
                if(root.right != null)stack.push(root.right);
                root = root.right;
            }
        }
        return res;
    }
}

不得不說反正我這兩個代碼還是遞歸性能比較高。不過我看了人家的迭代實現,比我要好看多了。。。我直接貼代碼了:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {

    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        if(root == null) return res;
        LinkedList<TreeNode> stack = new LinkedList<TreeNode>();
        stack.add(root);
        while(!stack.isEmpty()){
            root = stack.pollLast();
            res.add(root.val);
            if(root.right != null){
                stack.add(root.right);
            }
            if(root.left != null){
                stack.add(root.left);
            }
        }
        return res;
    }
}

emmmm....事實證明這段代碼人家提交超過百分百,我提交好幾次也都只超過百分之五十八。。和我之前的一樣的。。。行了行了,就這樣了,下一題是后續遍歷。

二叉樹的后序遍歷

題目:給定一個二叉樹,返回它的 后序 遍歷。進階: 遞歸算法很簡單,你可以通過迭代算法完成嗎?

思路:題目截圖就不截圖了,知道是后序遍歷就行了,我直接貼代碼了。
遞歸版本:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    List<Integer> res;
    public List<Integer> postorderTraversal(TreeNode root) {
        res = new ArrayList<Integer>();
        post(root);
        return res;
    }
    public void post(TreeNode root){
        if(root == null) return;
        post(root.left);
        post(root.right);
        res.add(root.val);
    }
}

迭代版本:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    
    public List<Integer> postorderTraversal(TreeNode root) {
        LinkedList<Integer> res = new LinkedList<Integer>();
        if(root == null) return res;
        LinkedList<TreeNode> stack = new LinkedList<TreeNode>();
        stack.add(root);
        while(!stack.isEmpty()){
            root = stack.poll();
            if(root.left !=null ) stack.push(root.left); 
            if(root.right != null) stack.push(root.right);
            res.addFirst(root.val);
        }
        return res;
    }
}

其實這個題就是上題的逆思路。遞歸就不說了,迭代的話如果是前序是 當前 + 左 +右。后續是 左 + 右 +當前。
其實左右是一樣的,但是當前要去后面。 換個思路 如果實現了 當前 +右 +左 則倒過來直接就是后序遍歷了。就這個思路。然后每次add都是添加到第一個,還有先放左再放右。
感覺也沒啥說的,剛剛做才發現后序遍歷是困難的,哈哈,突然對自己有信心了呢~~下一題了啊

LRU緩存機制

題目:運用你所掌握的數據結構,設計和實現一個 LRU (最近最少使用) 緩存機制。它應該支持以下操作: 獲取數據 get 和 寫入數據 put 。
獲取數據 get(key) - 如果密鑰 (key) 存在于緩存中,則獲取密鑰的值(總是正數),否則返回 -1。
寫入數據 put(key, value) - 如果密鑰不存在,則寫入其數據值。當緩存容量達到上限時,它應該在寫入新數據之前刪除最久未使用的數據值,從而為新的數據值留出空間。
進階:你是否可以在 O(1) 時間復雜度內完成這兩種操作?

示例:
LRUCache cache = new LRUCache( 2 /* 緩存容量 */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 該操作會使得密鑰 2 作廢
cache.get(2); // 返回 -1 (未找到)
cache.put(4, 4); // 該操作會使得密鑰 1 作廢
cache.get(1); // 返回 -1 (未找到)
cache.get(3); // 返回 3
cache.get(4); // 返回 4

思路:這個題怎么說呢,我覺得實現起來還是很簡單的,尤其是進階要求只要求了時間復雜度而沒有空間復雜度。。我目前的想法是用LinkedHashMap。然后put判斷下size,達到容量了則把第一個刪了,然后后一個加上。沒達到直接加。 然后get的時候先把這個key-value獲取了,然后把這個key刪除了,重新添加,保證用過的在最后,第一個的永遠是最不活躍的那個。。差不多就這樣,我去代碼實現下。
尷尬了,我發現LinkedHashMap自帶訪問順序,就是訪問完移到最后,,,哈哈。其實這個類我早就知道,但是工作中幾乎沒用到過,只知道是Linked(鏈表)+HashMap的合體,本來我以為只是有序的map呢。。。剛剛要用了去百度了下api才發現不太多。。我用這個數據結構是不是太取巧了啊?不管了,反正第一版本先實現再說。
好了,在前人的肩膀上直接實現了:

class LRUCache {
    LinkedHashMap<Integer,Integer> map;

    public LRUCache(int capacity) {
        this.map = new LinkedHashMap<Integer, Integer>(capacity, 0.75f, true) {
            @Override
            protected boolean removeEldestEntry(Map.Entry eldest) {
                return map.size() > capacity;
            }
        };
    }
    
    public int get(int key) {
        return map.get(key)==null?-1:map.get(key);
    }
    
    public void put(int key, int value) {
        map.put(key,value);
    }
}

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

我僅剩不多的自尊心告訴我這道題不是考對Linked Hash Map的熟悉程度的。。。我這是取巧了啊,我自己實現試試。
其實我覺得用LinkedList和HashMap也是可以實現的。鏈表存key,map的key還是key,value是value。然后鏈表就按照我剛剛說的,超了再放則刪除第一個。重復訪問則刪除再添加保證訪問的在最后。我去實現下看看。
自己手寫出來了,效率啥的賊辣眼睛。。。我先貼出來:

class LRUCache {
    int cap;
    HashMap<Integer,Integer> map;
    LinkedList<Integer> list;
    public LRUCache(int capacity) {
        this.cap = capacity;
        map = new HashMap<Integer,Integer>();
        list = new LinkedList<Integer>();
    }
    
    public int get(int key) {
        if(map.get(key) != null){
            list.remove(Integer.valueOf(key));
            list.add(key);
            return map.get(key);
        }
        return -1;
    }
    
    public void put(int key, int value) {
        if(list.size()==cap && !list.contains(key)){
            Integer r = list.get(0);
            list.remove(0);
            map.remove(r);
            list.add(key);
            map.put(key,value);
        }else if(list.contains(key)){//說明key已經存在,是更改值            
            list.remove(Integer.valueOf(key));
            list.add(key);
            map.put(key,value);
        }else{
            list.add(key);
            map.put(key,value);
        }

    }
}

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

就是linkedList 來排序, map來存值。難道是不難,就是很墨跡。這個題就這樣了。
今天的筆記就記到這里,如果稍微幫到你了記得點個喜歡點個關注,順便祝大家工作順順利利,生活平平安安,周末愉快!

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容