2023-04-03 动态规划--数组--栈与队列--二叉树

RemNow 动态规划–数组–栈与队列–二叉树

1.动态规划的五个步骤
  • 确定dp数组(dp table)以及下标的含义
  • 确定递推公式
  • dp数组如何初始化
  • 确定遍历顺序
  • 举例推导dp数组
  • 把下标为i的3个物品塞到背包最大装在量为4的里面,最多能装多少钱
//         物品:0  1  2
        int[] weight = {1,3,4};
        int[] value = {15,20,40};
        int bagSize = 4;
        //dp方程dp[i][j]定义是将i个物品放到背包容量为j的背包里,获得最多的钱!
        //有两种组成:一是不放入i的情况,那么最优解就是dp[i-1][j];即在下标为i-1的物品里面随便放,
        //放到大小为j的背包装最多的钱是
        dp[i-1][j]
        //情况二十放入i,那么就是i放入不会超标,所以i是能够放进去的,
        //所以要在dp[i-1][j]的基础上将i的重量扣掉才是最接近dp[i-1]的钱,即将(i-1)最值钱+i的最值钱
        dp[i-1][j-weight[i]]+value[i]
        //所以dp方程最大值是,放i或者不放i里面去最大值(有可能放i就超标了,所以又抠掉了一些数据)
        dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);
        

回归Demo

  1. 数组
    ※:数组是存放在连续内存空间上的相同类型数据的集合,数组的元素是不能删的,只能覆盖。
    ※:数组是.length-----string.length()------list.size()
    ※: int mid=(left+right+1)>>1;//向上取整数;(left+right)>>1向下取整
    ※:int minValue = Integer.MIN_VALUE;-------- int maxValue = Integer.MAX_VALUE;
    ※:记住map的遍历:
   for(Map.Entry<Integer,Integer> e:map.entrySet()){//遍历map里面的两个元素,取一下最大的频数
               int v=e.getValue();
               sum+=v;
           }

※:数组升序排序: Arrays.sort(nums);(1,2,3,6,9)
※:《算法与数据结构之美》:如何写出高效率的代码;设计模式:写出高质量代码;
※:StringBUffer

   		StringBuffer sb=new StringBuffer();
        sb.append("sdff");//拼接字符
        StringBuffer reverse = sb.reverse();//sb和reverse都是反转之后的字符
        char[] chars = s.toCharArray();
        StringBuilder sb=new StringBuilder(s);
 List<DemoClass> collect = list.stream().sorted(Comparator.comparing(DemoClass::getValue).reversed())
 .collect(Collectors.toList());
 
 List<Integer> collect = list.stream().sorted(Comparator.comparing(Integer::intValue).reversed())
 .collect(Collectors.toList());//加上reversed变倒叙
   List<Integer> ll = list.stream().sorted(Comparator.comparing(Integer::intValue))
   .collect(Collectors.toList());//正序排序
   
//stream流先按学生年龄降序排序,年龄相等的话,则按年级升级排序
resultList =  resultList.stream().sorted(Comparator.comparing(User::getAge)
                              .reversed()
                              .thenComparing(Comparator.comparing(User::getGrade).reversed())
                    ).collect(Collectors.toList());

  1. 栈与队列
    ※:栈的初始化以及常用方法

    	Stack<Integer> stackIn=new Stack<>();
        Integer pop = stackIn.pop();//弹出栈顶元素
        Integer peek = stackIn.peek();//查看栈顶元素
        Integer push = stackIn.push(5);//将元素存入栈
        boolean empty = stackIn.isEmpty();//判断栈是否为空
        int size = stackIn.size();//获取栈内容的长度
        栈擅长处理的是两个相邻元素的处理,因为后进先出
        
        Queue<Integer> queue=new LinkedList<>();
        Integer poll = queue.poll();//获取并移除此队列的头,如果此队列为空,则返回 null
        Integer peek = queue.peek();//获取队列的头但不移除此队列的头。如果此队列为空,则返回 null
        boolean offer = queue.offer(5);//如果超过了返回false
        boolean add = queue.add(5);//如果超出了抛出
        boolean empty = queue.isEmpty();//判断一个队列中是否为空。
        int size = queue.size();//获取队列内容的长度
    
    
    
    
  2. 二叉树(首先访问节点,其次处理节点)
    ※:递归三部曲
    1 确定入参出参数
    2 确定终止条件,一般放在第一行
    3 确定具体逻辑

    深度优先遍历DFS:
    二叉树前中后序遍:中左右,左中右,左右中

        postorder(root.left, list);
        postorder(root.right, list);
        list.add(root.val); (这一句)
        //递归遍历二叉树的话,就是list.add放的位置,决定前中后顺序
        栈迭代法实现前序遍历
       public static List<Integer> preOrderStack(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()) {
            TreeNode peek = stack.peek();
            result.add(stack.pop().val);//每次处理的都是当前节点
            if (null!=peek.right) stack.push(peek.right);//利用栈先进先出的规则,不断给把当前节点的右、左节点加入
            if (null!=peek.left) stack.push(peek.left);
        }
        return result;
    }
       

栈实现后序遍历

     //栈模拟后序遍历leetCOde144
    public static List<Integer> afterOrderStack(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()) {
            TreeNode peek = stack.peek();
            result.add(stack.pop().val);//每次处理的都是当前节点
            
            if (null!=peek.left) stack.push(peek.left);
            if (null!=peek.right) stack.push(peek.right);//利用栈先进先出的规则,不断给把当前节点的右、左节点加入
        }
        Collections.reverse(result);//将list里面的顺序颠倒一下
        return result;
    }

用栈实现中序遍历

public List<Integer> inorderTraversal(TreeNode root){
          List<Integer> result = new ArrayList<>();//记录结果
        Stack<TreeNode> stack = new Stack<>();//记录遍历的节点啊
       TreeNode cur=root;
        while (!stack.isEmpty() || null!=cur) {//栈不为空,或者节点不为空就是没处理完
           if (cur!=null){//先向左延伸,记录不为空节点
               stack.push(cur);//用栈来接收节点
               cur=cur.left;//用指针来记录节点
           }else{//如果节点为空,就操作栈弹出元素
             TreeNode pop = stack.pop();
             result.add(pop.val);
             cur= pop.right;//上一步是node.left为null了,所以下一步查找node.right
           }
        }
        return result;
        //总之,node不为空就塞到栈里面去,node为空的话栈就弹出元素
        }

广度优先遍历BFS(层序遍历):

//l力扣102:程序遍历
    public List<List<Integer>> levelOrder(TreeNode root) {
        if (null==root) return new ArrayList<>();//判空
        List<List<Integer>> list=new ArrayList<>();//记录结果集
        Queue<TreeNode> queue=new LinkedList<>();
        queue.add(root);//将根节点加入队列,先进先出
        int size=1;//第一层的长度设定
        while(!queue.isEmpty()){//当队列里面还有元素,就不能终止
            List<Integer> l=new ArrayList<>();//记录返回的list
            while (size>0){
                TreeNode poll = queue.poll();//弹出一个元素,
                l.add(poll.val);//将元素加入l
                TreeNode left = poll.left;//将左右元素加入队列
                TreeNode right = poll.right;
                if (null!=left) queue.add(left);
                if (null!=right) queue.add(right);
                size--;
            }
            list.add(l);//将程序遍历的结果存入结果集
            if (queue.size()!=0) size=queue.size();//如果队列里面没有元素了,说明层的下一层元素全部为null,即到达二叉树的结尾
        }
        return  list;//返回结果集
    }

层序遍历递归,巧思

 public List<List<Integer>> resList = new ArrayList<List<Integer>>();
    public List<List<Integer>> levelOrder(TreeNode root) {
     checkFun0ZTs(root,0);
       return resList;
    }

    public  void checkFun0ZTs(TreeNode node, Integer deep){
        if (null==node) return;
        deep++;//走到这一步的意思是,下一层节点不为空,如果resList里面没有创建一个list来接收参数,那就需要添加一个
        if (resList.size()<deep){//说明resList里面还没有添加进这个list,需要加进去
            resList.add(new ArrayList<Integer>());
        }
        resList.get(deep-1).add(node.val);//巧妙利用了deep,和创建deep个list添加到结果集合里面
        checkFun0ZTs(node.left,deep);
        checkFun0ZTs(node.right,deep);
}

链表也是list的实现类,所以

  LinkedList<List<Integer>> result = new LinkedList<>();
  result.addFirst(xxx);//往队列的头插入数据,
  result.addLast(xxx);//往队列的尾部插入数据,
  return List<List<Integer>>;//可以控制list的顺序

力扣107

 public List<List<Integer>> levelOrderBottom(TreeNode root) {
 		LinkedList<List<Integer>> result = new LinkedList<>();
        if (root == null) return result;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            List<Integer> oneLevel = new ArrayList<>();
            // 每次都取出一层的所有数据
            int count = queue.size();
            for (int i = 0; i < count; i++) {
                TreeNode node = queue.poll();
                oneLevel.add(node.val);
                if (node.left != null) queue.add(node.left);
                if (node.right != null) queue.add(node.right);
            }
            // 每次都往队头塞
            result.addFirst(oneLevel);
        }
        return result;
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值