剑指offer——其三

关于ArrayList是import java.util.ArrayList;包中的

list.add(data);//添加data到list尾部
list.add(index,data);//添加data到index位置
list.remove(index);//删除下标为index的data
list.removeRange(start,end);//删除下标从start到end结束的data
list.clear();//清空列表

list.get(index);//获得下标为index的数据
list.set(index,new_data);//修改下标为index的数据为new_data

list.contains(data);//包含data,返回true
list.indexOf(data);//返回data在列表中第一次出现的位置,没有该元素返回-1
list.last Index Of(data);//返回data在列表中最后一次出现的位置,没有该元素返回-1

list.isEmpty();//列表为空返回true

list.size();//返回列表长度

//对ArrayList进行遍历
for(Object obj:list){
	对obj进行操作;

//还有一种Iterator遍历的方法,
Iterator<Object> iterator = lst.iterator();
//iterator.hasNext()如果存在元素的话返回true
while(iterator.hasNext()) {
//iterator.next()返回迭代的下一个元素
System.out.println(iterator.next());
    }
}

然后说说LinkedList

list.getFirst();//获得头元素
list.getLast();//获得尾元素
list.get(index);//获得下标为index的元素
list.indexOf(data);//获得data的下标

//遍历链表
for(Object obj:list){
	对obj进行操作
}

list.subList(start,end);//生成下标从start开始到end结束的子链表
list.add(data);//将data添到链表最后
list.add(index,data);//添加data到下标为index的位置
list.addFirst(data);//添加data到链头
list.addLast(data);//添加data到链尾

list.remove(data);//删除data元素
list.remove(index);//删除下标为index的元素
list.removeFirst();//删除头元素
list.removeLast();//删除尾元素
list.clear();//清空链表
list.subList(start,end).clear();//删除指定范围内的data

二叉树

对称二叉树或者镜像二叉树

请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

肯定是用递归的,也就是设两个root节点,当左root的left=右root的right同时左root的right=右root的left,肯定对称

public class Solution {
    boolean isSymmetrical(TreeNode pRoot)
    {
        if(pRoot==null) return true;
      return isSymme(pRoot.left,pRoot.right);
    }
  boolean isSymme(TreeNode root1,TreeNode root2)
    {
        if(root1==null&&root2==null) return true;
    if(root1==null||root2==null) return false;
    if(root1.val!=root2.val) return false;
    return isSymme(root1.left,root2.right)&&isSymme(root1.right,root2.left); 
    }
}

之字形打印二叉树

即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

我的思路:使用两个栈,一个奇数层用一个偶数层用
另一种思路,记录每层的大小,奇数层正着输入,偶数层反着输入

public class Solution {
    public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
      ArrayList<ArrayList<Integer>> res=new ArrayList<>();
      LinkedList<TreeNode> q=new LinkedList<>();
      boolean rev=true;//判断奇偶层
      q.add(pRoot);
      while(!q.isEmpty()){
        int size=q.size();
        ArrayList<Integer> list=new ArrayList<>();
        for(int i=0;i<size;i++){
          TreeNode node=q.poll();
          if(node==null) continue;
          if(rev){
            list.add(node.val);
          }else
            list.add(0,node.val);
          q.offer(node.left);
          q.offer(node.right);
        }
        if(list.size()!=0) res.add(list);
        rev=!rev;
      }
      return res;
    }

使用递归进行层序遍历

public class Solution {
    ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        ArrayList<ArrayList<Integer>> list = new ArrayList<>();
        depth(pRoot, 1, list);
        return list;
    }
     
    private void depth(TreeNode root, int depth, ArrayList<ArrayList<Integer>> list) {
        if(root == null) return;
        if(depth > list.size())//将层数与当前存的arraylist比较,arraylist小了就再添一行
            list.add(new ArrayList<Integer>());
        list.get(depth -1).add(root.val);//添加到相应的层数就行
         
        depth(root.left, depth + 1, list);
        depth(root.right, depth + 1, list);
    }
}

二叉树的序列化和反序列化

二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。

二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。

这个半命题层序遍历挺简单的,但是我用先序遍历尝试一下

序列化
void BST_Preorder(TreeNode node,String data){
	if(!node) {data+="#!"; return;}
	String str=node.val+"!";
	data+=str;
	BST_Preorder(node->left,data);
	BST_Preorder(node->right,data);
} 
String[] str=data.split("!");
反序列化
int index=0;
TreeNode out_BST_order(String[] str){
	if(str[index].equals("#"){
		index++;
		return null;
	}
	TreeNode root=new TreeNode(Integer.valueOf(str[index]);
	index++;
	root.left(out_BST_order(str));
	root.right(out_BST_ordr(str));
	return root;
}

给定一棵二叉搜索树,请找出第k小的节点

二叉搜索树:就是左子树<根节点<右子树

public class Solution {
  ArrayList<TreeNode> list=new ArrayList<>();
    TreeNode KthNode(TreeNode pRoot, int k)
    {
        if(pRoot==null||k<=0) return null;
         Search(pRoot,k);
        if(k>list.size())
          return null;
      return list.get(k-1);
    }
void Search(TreeNode pRoot, int k)
    {
      if(pRoot!=null) {
        if(k<=list.size()){
          return;
        }
        Search(pRoot.left,k);
        list.add(pRoot);
        Search(pRoot.right,k);
      }
    }

大小顶堆求中位数

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

import java.util.*;
public class Solution {
    private int cnt=0;
     PriorityQueue<Integer> low=new PriorityQueue<>();//小顶堆
     PriorityQueue<Integer> high=new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2)
            {
                return o2 - o1;
            }
        });//大顶堆

    public void Insert(Integer num) {
    if(high.isEmpty()){
      high.offer(num);
      return;
    }
      if(high.size()==low.size()){
        if(num<high.peek())
          high.offer(num);
        else
          low.offer(num);
      }else if(high.size()>low.size()){
        if(num>high.peek())
          low.offer(num);
        else{
          low.offer(high.peek());
          high.poll();
          high.offer(num);
        } 
      }else if(high.size()<low.size()){
        if(num<low.peek())
          high.offer(num);
        else{
          high.offer(low.peek());
          low.poll();
          low.offer(num);
        }
      }
    }

    public Double GetMedian() {
      double res=0;
      if(high.size()==low.size())
        return (high.peek()+low.peek())/2.0;
      else if(high.size()>low.size())
        res= high.peek();
      else
        res= low.peek();
      return res;
    }
}

滑动窗口最小数

给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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]}

采用最大堆维护堆顶元素,最简洁

import java.util.*;
public class Solution {
    public ArrayList<Integer> maxInWindows(int [] num, int size)
    {
      ArrayList<Integer> res=new ArrayList<>();
      if(num==null||size<=0||num.length<size) return res;
      PriorityQueue<Integer> queue=new PriorityQueue<Integer>((o1,o2)->o2-o1);//构建最大堆
        for(int i=0;i<size;i++){
           queue.offer(num[i]);
        }//先输入最开始的size个元素
      res.add(queue.peek());
      for(int i=size;i<num.length;i++){//接下来的元素,进一个,出一个取堆顶入res
        queue.remove(num[i-size]);
        queue.offer(num[i]);
        res.add(queue.peek());
      }
        return res;
    }
}
posted @ 2020-06-11 09:46  梅落南山  阅读(144)  评论(0编辑  收藏  举报