劍指offer 60-63

第60題

題目描述:
請實現兩個函數,分別用來序列化和反序列化二叉樹

二叉樹的序列化是指:把一棵二叉樹按照某種遍歷方式的結果以某種格式保存爲字符串,從而使得內存中建立起來的二叉樹可以持久保存。序列化可以基於先序、中序、後序、層序的二叉樹遍歷方式來進行修改,序列化的結果是一個字符串,序列化時通過 某種符號表示空節點(#),以 ! 表示一個結點值的結束(value!)。

二叉樹的反序列化是指:根據某種遍歷順序得到的序列化字符串結果str,重構二叉樹。

例如,我們可以把一個只有根節點爲1的二叉樹序列化爲"1,",然後通過自己的函數來解析回這個二叉樹。

算法分析:
一般解決二叉樹的問題都可以使用遞歸。序列化的時候比較簡單,但是要注意使用"#"表示空結點,有助於後面逆序列化的操作。逆序列化的時候我們要對字符串進行分割,分割成字符數組。逆序列化的過程類似序列化的過程。

代碼如下:

public class Solution {
    //序列化二叉樹
    //數與數之間以","間隔,便於反序列化的時候分割
    int index;
    String Serialize(TreeNode root) {
        StringBuilder sb = new StringBuilder();
        //結束條件,非常重要
        if(root==null){
            sb.append("#,");
            return sb.toString();
        }
        sb.append(root.val+",");
        sb.append(Serialize(root.left));
        sb.append(Serialize(root.right));
        return sb.toString();
  }
    //反序列化二叉樹
    TreeNode Deserialize(String str) {
        if(str==null){
            return null;
        }
        index = -1;
        String[] strArray = str.split(",");
        return DeserializeStr(strArray);
  }
    public TreeNode DeserializeStr(String[] strArray){
        
        index++;
        TreeNode treeNode = null;
        //沒到最終結點
        if(!strArray[index].equals("#")){
            treeNode = new TreeNode(Integer.parseInt(strArray[index]));
            treeNode.left = DeserializeStr(strArray);
            treeNode.right = DeserializeStr(strArray);
        }
        return treeNode;
    }
}

第61題

題目描述:
給定一棵二叉搜索樹,請找出其中的第k小的結點。例如, (5,3,7,2,4,6,8) 中,按結點數值大小順序第三小結點的值爲4。

思路分析:
二叉搜索樹滿足根節點左子樹的結點值全部小於根節點,根節點右子樹的值全部大於根節點。所以當對二叉搜索樹按中序序列遍歷時,得到的剛好是從小到大的序列。

代碼如下:

public class Solution {

    //二叉搜索樹按中序遍歷順序打印即爲從小到大打印一棵樹
    TreeNode KthNode(TreeNode pRoot, int k)
    {
        if(pRoot == null || k<1){
            return null;
        }
        
        int index = 0;
        //藉助棧實現二叉樹中序的非遞歸遍歷
        Stack<TreeNode> stack =new Stack<TreeNode>();
        while(pRoot!=null || !stack.isEmpty()){
            while(pRoot!=null){
                stack.push(pRoot);
                pRoot = pRoot.left;
            }
            pRoot = stack.pop();
            index ++;
            if(index == k){
                return pRoot;
            }
            pRoot = pRoot.right;
        }
        return null;
        
    }
}

第62題

題目描述:
如何得到一個數據流中的中位數?如果從數據流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。如果從數據流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。我們使用Insert()方法讀取數據流,使用GetMedian()方法獲取當前讀取數據的中位數。

思路分析:
在這裏插入圖片描述在這裏插入圖片描述
代碼如下:

public class Solution {

    //從小到大排序
    PriorityQueue<Integer> minHeap =  new PriorityQueue<Integer>();
    //從大到小排序
    PriorityQueue<Integer> maxHeap =  new PriorityQueue<Integer>((o1,o2)->{
        return o2 - o1;
    });
    
    int count = 0;
    
    public void Insert(Integer num) {
        //爲偶數
        if(count%2==0){
            maxHeap.offer(num);
            minHeap.offer(maxHeap.poll());
        }else{
            //爲奇數
            minHeap.offer(num);
            maxHeap.offer(minHeap.poll());
        }
        count++;
    }

    public Double GetMedian() {
        if(count%2==0){
            return new Double(minHeap.peek()+maxHeap.peek())/2;
        }
        return new Double(minHeap.peek());
    }
}

第63題

題目描述:
給定一個數組和滑動窗口的大小,找出所有滑動窗口裏數值的最大值。例如,如果輸入數組{2,3,4,2,6,2,5,1}及滑動窗口的大小3,那麼一共存在6個滑動窗口,他們的最大值分別爲{4,4,6,6,6,5}; 針對數組{2,3,4,2,6,2,5,1}的滑動窗口有以下6個: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。

思路分析:
滑動窗口應當是隊列,但爲了得到滑動窗口的最大值,隊列序可以從兩端刪除元素,因此使用雙端隊列。
原則:
對新來的元素k,將其與雙端隊列中的元素相比較
1)前面比k小的,直接移出隊列(因爲不再可能成爲後面滑動窗口的最大值了!),
2)前面比k大的X,比較兩者下標,判斷X是否已不在窗口之內,不在了,直接移出隊列隊列的第一個元素是滑動窗口中的最大值。

代碼如下:

public class Solution {
    public ArrayList<Integer> maxInWindows(int [] num, int size)
    {
        //用於存儲最後的結果
        ArrayList<Integer> result = new ArrayList<>();
        if (num == null) {
            return result;
        }
        if (num.length < size || size < 1) {
            return result;
        }
        //用做雙向鏈表,存儲的是元素的下標 
        LinkedList<Integer> indexDeque = new LinkedList<>();
        
        for(int i=0;i<num.length;i++){
            //當新進的元素大於數組中最後一個元素(最小值),刪除最小值
            while(!indexDeque.isEmpty()&&num[i]>num[indexDeque.getLast()]){
                indexDeque.removeLast();
            }
            indexDeque.addLast(i);
            //判斷隊列首部是否過期
            if(indexDeque.getFirst() == i - size){
                indexDeque.removeFirst();
            }
            //從第三個值開始往result添加元素
            if(i>=size-1){
                result.add(num[indexDeque.getFirst()]);
            }
        }
        return result;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章