剑指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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值