zoukankan      html  css  js  c++  java
  • 剑指offer——其三


    LinkedList和ArrayList要好好研究一下

    ArrayList和LinkedList的大致区别:

    1. ArrayList是实现了基于动态数组的数据结构,LinkedList是基于链表结构
    2. 对于随机访问的get和set方法,ArrayList要优于LinkedList
    3. 对于新增和删除操作add和remove,LinkedList比较占优势

    个人理解可能是ArrayList是种顺序结构,而LinkedList是种链式结构,双向链表

    ArrayList使用在查询比较多,但是插入和删除比较少的情况,而LinkedList用在查询比较少而插入删除比较多的情况

    首先说ArrayList

    关于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;
        }
    }
  • 相关阅读:
    01 . Nginx简介及部署
    01 . Ansible原理部署及简单应用
    vue css module
    Expected linebreaks to be 'LF' but found 'CRLF'.
    vue SPA设计 history hash
    vue3 createComponent
    vue3 template refs dom的引用、组件的引用、获取子组件的值
    vue3 父组件给子组件传值 provide & inject
    vue3生命周期
    CSS3 transform变换
  • 原文地址:https://www.cnblogs.com/ting65536/p/13091415.html
Copyright © 2011-2022 走看看