LeetCode(2)

目录

概念解释

 队列

树的概念 

 结点的分类

有序树

无序树

森林 

二叉树

满二叉树

完全二叉树

 二叉排序树

平衡二叉树 

1.用栈实现队列

解法:双栈 

 2.字符串解码

 解法:栈

3.二叉树的中序遍历

 解法一:递归

解法二:迭代 

4.二叉树的前序遍历 

解法一:递归

 解法二:迭代

5.二叉树的后序遍历

 6.平衡二叉树

自底向上的递归 

7.二叉树的最大深度

 解法一:迭代

解法二:递归 

8.对称二叉树

解法一:递归 

解法二:迭代 


概念解释

栈(堆栈) : 后进先出的结构,Last In First Out,简称LIFO结构。

 队列

先进先出的结构,First In First Out,简称FIFO结构。

树(Tree)是n(n >= 0)个结点的有限集合,当n=0时,称为空树。

在任意一个非空树中应满足:

        1.有且仅有一个特定的称为根(Root)的结点。

        2.当n>1时,其余节点可分成m(m>0)个互不相交的有限集合T1,T2,...Tm,其中每个集合本身又是一棵树,并且称为根结点的子树(SubTree)。

树的概念 

结点的度:结点拥有的子树的数量;

结点的深度(层次):从上往下数,结点距离根结点的距离。

结点的高度:从下往上数,结点在第几层,结点的高度就是多少;

树的高度:结点深度最大的那个结点的深度就是树的深度;

树的度:树中度最大结点的度就是树的度。

 结点的分类

叶子节点:度为0的结点;

分支结点(内部结点):度不为0的结点(除根节点)。

有序树

从逻辑上看,树中结点的各子树从左至右是有次序的,不能互换。

无序树

从逻辑上看,树中结点的各子树从左至右是无次序的,可以互换。

森林 

m(m>=0)棵互不相交的树的集合。

二叉树

二叉树是n(n>=0)个结点的有限集合;

可以是空二叉树,即n=0;

可以是由一个根节点和两个互不相交的树(被称为根的左子树和右子树)组成。

左子树和右子树又分别是一课二叉树。、

特点:每个结点最多只有两棵子树;

           左右子树不能颠倒(二叉树是有序树)

满二叉树

每层结点的个数都达到最大值;即如果一个二叉树的层数为k,并且总结点数位2^{k}-1,那么这个数就是满二叉树。

特点:1.最后一层都是叶子节点;

           2.不存在度为1的结点;

           3.按层序从1开始编号,结点i的左孩子为2i,右孩子为2i+1;

               结点i的父结点为i/2向下取整。

完全二叉树

当且仅当其每个结点都与满二叉树中编号位1-n的结点一一对应时,称为完全二叉树。

即,相比于满二叉树,完全二叉树少一个右下角。

特点:1.只有最后两层可能又叶子结点;

           2.最多只有一个度为1的结点;

           3.按层序从1开始编号,结点i的左孩子为2i,右孩子为2i+1;

               结点i的父结点为i/2向下取整。

           4.如果一个完全二叉树的有n个结点,那么,当结点的编号i<=n/2向下取整,那么这些结点为分支结点;当结点的编号i>n/2向下取整,那么这些结点为叶子结点;

 二叉排序树

左子树上所有结点的关键字均小于根节点的关键字,右子树上所有结点的关键字均大于根节点的关键字;左子树和右子树又各是一棵二叉排序树。

平衡二叉树 

树上任一结点的左子树和右子树的深度之差不超过1.

1.用栈实现队列

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

说明:

  • 你 只能 使用标准的栈操作 —— 也就是只有 push to toppeek/pop from topsize, 和 is empty 操作是合法的。
  • 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可

进阶:

  • 你能否实现每个操作均摊时间复杂度为 O(1) 的队列?换句话说,执行 n 个操作的总时间复杂度为 O(n) ,即使其中一个操作可能花费较长时间。

解法:双栈 

利用双栈就可以实现队列,一个做输入栈,一个做输出栈。

队列是先进先出,栈刚好相反,但如果,先把数据压入输入栈,再从输入栈将数据压入输出栈,就和队列一样了。

class MyQueue {
    private static Stack<Integer> inStack;
    private static Stack<Integer> outStack;

    public MyQueue() {
        inStack = new Stack<Integer>();
        outStack = new Stack<Integer>();
    }
    
    public void push(int x) {
        inStack.push(x);
    }
    
    public int pop() {
        if(outStack.isEmpty()){
            inToOut();
        }
        return outStack.pop();
    }
    private void inToOut(){
        //如果输入栈非空,将输入栈的元素弹出,然后压入输出栈
        while(!inStack.isEmpty()){
            outStack.push(inStack.pop());
        }
    }
    
    public int peek() {
        if(outStack.isEmpty()){
            inToOut();
        }
        return outStack.peek();
    }
    
    public boolean empty() {
            return inStack.isEmpty() && outStack.isEmpty();
    }
}

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue obj = new MyQueue();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.peek();
 * boolean param_4 = obj.empty();
 */

 2.字符串解码

给定一个经过编码的字符串,返回它解码后的字符串。

编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。

你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。

此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。

 

 解法:栈

 本题考查我们对栈的操作。

以3[a]2[bc]为例,我们从3开始入栈;

如果是数字,将数字进行解析,然后进栈,

如果是 [ 或者 字母,直接进栈,

如果是 ] ,开始出栈,直到遇到 [ 为止。

class Solution {
    public String decodeString(String s) {
        //存数字的栈
        Stack<Integer> countStack = new Stack<>();
        //存字母或 [ ] 的栈
        Stack<String> resStack = new Stack<>();
        //初始下标
        int index = 0;
        int len = s.length();
        String res = "";
        while(index < len){
            char ch = s.charAt(index);
            //处理数字
            if(Character.isDigit(ch)){
                StringBuffer sb = new StringBuffer();
                //如果是数字,就加到sb中
                while(Character.isDigit(s.charAt(index))){
                    sb.append(s.charAt(index++));
                }
                countStack.push(Integer.parseInt(sb.toString()));
            }else if(ch == '['){
                //当ch为[ 时,让res入栈,将res置空
                resStack.push(res);
                res = "";
                index++;
            }else if(ch == ']'){
                //当ch为]时,开始出栈
                StringBuffer temp = new StringBuffer(resStack.pop());
                int repeaTims = countStack.pop();
                for(int i = 0;i<repeaTims;i++){
                    temp.append(res);
                }
                res = temp.toString();
                index++;
            }else{
                //当ch为字母时,拼接到res后面
                res += s.charAt(index++);
            }
        }
        return res;
    }
}

3.二叉树的中序遍历

给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。

进阶: 递归算法很简单,你可以通过迭代算法完成吗? 

 解法一:递归

 首先,我们要知道二叉树的中序遍历是什么,根节点-左子树-右子树,而且在访问左子树或右子树时,还是同样的方式,直到整个树遍历完,终止条件就是当结点为空时,中止。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        accessTree(root,res);
        return res;
    }
    public void accessTree(TreeNode root,List<Integer> res){
        if(root == null){
            return;
        }
        accessTree(root.left,res);
        res.add(root.val);
        accessTree(root.right,res);
    }
}

时间复杂度:O(n)
空间复杂度:O(n)

解法二:迭代 

 题目要求使用迭代。

首先,我们要明确中序遍历的步骤:左、根、右;所以先访问左子树,但是根节点的值需要保存下来,因为我们为了效率,必须保证每个结点只访问了一次。

我们引入一个栈用来保存根节点。

迭代步骤:先将根节点压入栈,然后访问左子树,如果左子树不为空,继续将左子树的根节点压入栈,如果左子树为空,将其弹出栈然后输出,在访问右子树,直到整个树遍历完。

public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        while(root != null || !stack.isEmpty()){
            while(root!=null){
                stack.push(root);
                root = root.left;
            }
            root = stack.pop();
            res.add(root.val);
            root = root.right;
        }
        return res;
    }

时间复杂度:O(n)
空间复杂度:O(n) 

4.二叉树的前序遍历 

 给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

 和中序遍历思路一样。

要注意的是遍历顺序:根节点、左子树、右子树

解法一:递归

public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        accessTree(root,res);
        return res;
    }
    public void accessTree(TreeNode root,List<Integer> res){
        //终止条件
        if(root==null){
            return;
        }
        //先访问根节点
        res.add(root.val);
        //左子树
        accessTree(root.left,res);
        //右子树
        accessTree(root.right,res);
    }

  时间复杂度:O(n)
空间复杂度:O(n)

 解法二:迭代

public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        while(root!=null || !stack.isEmpty()){
            while(root!=null){
                res.add(root.val);
                stack.push(root);
                root = root.left;
            }
          root =  stack.pop();
          root = root.right;

        }
        return res;
    }

时间复杂度:O(n)
空间复杂度:O(n)  

5.二叉树的后序遍历

给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历 

进阶:递归算法很简单,你可以通过迭代算法完成吗?

递归跟前两个思路一样,但是迭代就差很多,这是因为后序遍历的步骤是左子树、右子树、根节点,每次需要遍历右子树时,都需要借助根结点,所以这里需要定义一个空结点,每次都要保存根节点。

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        if (root == null) {
            return res;
        }

        Deque<TreeNode> stack = new LinkedList<TreeNode>();
        TreeNode prev = null;
        while (root != null || !stack.isEmpty()) {
            while (root != null) {
                stack.push(root);
                root = root.left;
            }
            root = stack.pop();
            if (root.right == null || root.right == prev) {
                res.add(root.val);
                prev = root;
                root = null;
            } else {
                stack.push(root);
                root = root.right;
            }
        }
        return res;
    }
}

 6.平衡二叉树

给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:

一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。

自底向上的递归 

public boolean isBalanced(TreeNode root) {
        
       return height(root) != -1;

    }
    public int height(TreeNode root){
        if(root == null){
            return 0;
        }
        //从左子树开始判断
        int leftH = height(root.left);
        int rightH = height(root.right);
        if(leftH == -1 || rightH == -1 || (leftH-rightH) > 1||(rightH-leftH)>1){
            return -1;
        }
        return leftH > rightH ? (leftH + 1):(rightH + 1);
    }

7.二叉树的最大深度

给定一个二叉树 root ,返回其最大深度。

二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。

 解法一:迭代

使用队列里存放当前层的所有节点。每次拓展下一层的时候,我们需要将队列里的所有节点都拿出来进行拓展,这样能保证每次拓展完的时候队列里存放的是当前层的所有节点,即我们是一层一层地进行拓展,最后我们用一个变量 ans\textit{ans}ans 来维护拓展的次数,

public int maxDepth(TreeNode root) {
        if(root == null){
            return 0;
        }
       Queue<TreeNode> q = new LinkedList<>();
       int count = 0;
       q.offer(root);
       while(!q.isEmpty()){
           int size = q.size();
           while(size>0){
               TreeNode n = q.poll();
               if(n.left != null){
                   q.offer(n.left);
               }
               if(n.right!=null){
                   q.offer(n.right);
               }
               size--;
           }
           count++;
       }
       return count;
    }

解法二:递归 

如果我们知道了左子树和右子树的最大深度 l和 r,那么该二叉树的最大深度即为

max⁡(l,r)+1.
而左子树和右子树的最大深度又可以以同样的方式进行计算。

public int maxDepth(TreeNode root) {
        if(root == null){
            return 0;
        }
       int l = maxDepth(root.left);
       int r = maxDepth(root.right);
        return l > r ? l + 1 : r +1;
    }

8.对称二叉树

给你一个二叉树的根节点 root , 检查它是否轴对称。

 

解法一:递归 

乍一看使用递归很好解决。
根据题目的描述,镜像对称,就是左右两边相等,也就是左子树和右子树是相当的。
注意这句话,左子树和右子相等,也就是说要递归的比较左子树和右子树。

class Solution {
	public boolean isSymmetric(TreeNode root) {
		if(root==null) {
			return true;
		}

		return dfs(root.left,root.right);
	}
	
	boolean dfs(TreeNode left, TreeNode right) {

		if(left==null && right==null) {
			return true;
		}
		if(left==null || right==null) {
			return false;
		}
		if(left.val!=right.val) {
			return false;
		}

		return dfs(left.left,right.right) && dfs(left.right,right.left);
	}
}

解法二:迭代 

首先我们引入一个队列。初始化时我们把根节点入队两次。每次提取两个结点并比较它们的值(队列中每两个连续的结点应该是相等的,而且它们的子树互为镜像),然后将两个结点的左右子结点按相反的顺序插入队列中。当队列为空时,或者我们检测到树不对称(即从队列中取出两个不相等的连续结点)时,该算法结束。

class Solution {
    public boolean isSymmetric(TreeNode root) {
        return check(root, root);
    }

    public boolean check(TreeNode u, TreeNode v) {
        Queue<TreeNode> q = new LinkedList<TreeNode>();
        q.offer(u);
        q.offer(v);
        while (!q.isEmpty()) {
            u = q.poll();
            v = q.poll();
            if (u == null && v == null) {
                continue;
            }
            if ((u == null || v == null) || (u.val != v.val)) {
                return false;
            }

            q.offer(u.left);
            q.offer(v.right);

            q.offer(u.right);
            q.offer(v.left);
        }
        return true;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/355575.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据结构(一)------顺序表

文章目录 前言一、什么是顺序表二、实现顺序表1.静态顺序表2.动态顺序表总结 前言 制作不易&#xff01;三连支持一下呗&#xff01;&#xff01;&#xff01; 从今天起我们将会进入数据结构的学习&#xff01; 我们先来了解 什么是数据结构 数据结构是计算机存储、组织数…

喜报|「云原生数据库PolarDB」、「阿里云瑶池一站式数据管理平台」揽获“2023技术卓越奖”

日前&#xff0c;国内知名IT垂直媒体&技术社区IT168公布2023年“技术卓越奖”评选结果&#xff0c;经由行业CIO/CTO大咖、技术专家及IT媒体三方的联合严格评审&#xff0c;阿里云瑶池数据库揽获两项大奖&#xff1a;云原生数据库PolarDB荣获“2023年度技术卓越奖”&#xf…

分布式ID(3):雪花算法生成ID之UidGenerator(百度开源的分布式唯一ID生成器)

1 UidGenerator官方地址 UidGenerator源码地址: https://github.com/baidu/uid-generator UidGenerator官方说明文档地址: https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md 这边只做简单介绍,详细说明请看官方说明文档。 2 Snowflake算法 Snowfl…

VMware中CentOS 7解决网络问题

问题描述 在 VMware 中使用 CentOS 7 中使用 ping www.baidu.com 测试网络是否能正常连接。 出现了未知的名称和服务的问题&#xff1a; 解决方案一 在服务中检查 VMware NAT Service 是否开启 解决方案二 在控制面板中的网络适配器里检查 解决方案三 检查VMware中的网络适…

SpringBoot常见错误

SpringBoot常见错误 1、SpringBoot启动时报错 错误: 找不到或无法加载主类 com.xxx.xxx.Application springboot启动时报错错误&#xff1a;找不到或无法加载主类 com.xxx.xxx.Application。 解决方法就是打开idea的控制台&#xff0c;输入以下三行命令&#xff1a; mvn cl…

遗传算法求解基于移动边缘计算的任务卸载与资源调度优化(提供MATLAB代码)

一、优化模型介绍 移动边缘计算的任务卸载与资源调度优化原理是通过利用配备计算资源的移动无人机来为本地资源有限的移动用户提供计算卸载机会&#xff0c;以减轻用户设备的计算负担并提高计算性能。具体原理如下&#xff1a; 任务卸载&#xff1a;移动边缘计算系统将用户的计…

SV-7042C 标准TCP协议网络有源音柱

SV-7042C 标准TCP协议网络有源音柱 一、描述 SV-7042C是深圳锐科达电子有限公司的一款壁挂式网络有源音柱&#xff0c;具有10/100M以太网接口&#xff0c;可将网络音源通过自带的功放和喇叭输出播放&#xff0c;其采用防水设计&#xff0c;功率可以从20W到40W。SV-7042C作为网…

小土堆pytorch学习笔记003 | 下载数据集dataset 及报错处理

目录 1、下载数据集 2、展示数据集里面的内容 3、DataLoader 的使用 例子&#xff1a; 结果展示&#xff1a; 1、下载数据集 # 数据集import torchvisiontrain_set torchvision.datasets.CIFAR10(root"./test10_dataset", trainTrue, downloadTrue) test_set …

深入了解Redis:选择适用于你的场景的持久化方案

自然语言处理的发展 文章目录 自然语言处理的发展强烈推荐前言&#xff1a;Redis提供了几种主要的持久化方案&#xff1a;RDB快照持久化&#xff1a;工作原理&#xff1a; AOF日志文件持久化&#xff1a;混合持久化&#xff1a; 总结强烈推荐专栏集锦写在最后 强烈推荐 前些天…

第五篇:express路由路径方式(字符串,字符串模式,和正则)

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 &#x1f4d8; 引言&#xff1a; &#x1f4…

JVM篇----第十篇

系列文章目录 文章目录 系列文章目录前言一、JAVA 强引用二、JAVA软引用三、JAVA弱引用四、JAVA虚引用五、分代收集算法前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧…

CVPR——Latex模版下载

CVPR官网 -> AuthorGuidelines 链接&#xff1a;AuthorGuidelines

备战蓝桥杯---数据结构与STL应用(基础3)

今天我们主要介绍的是pair,string,set,map pair:我们可以把它当作一个结构体&#xff1a; void solve(){pair<int int> a;//创建amake_pair(1,2);//添加元素cout<<a.first<<endl<<a.second<<endl;}//输出 当然&#xff0c;它也可以嵌套&#…

Qt/C++音视频开发64-共享解码线程/重复利用解码/极低CPU占用/画面同步/进度同步

一、前言 共享解码线程主要是为了降低CPU占用&#xff0c;重复利用解码&#xff0c;毕竟在一个监控系统中&#xff0c;很可能打开了同一个地址&#xff0c;需要在多个不同的窗口中播放&#xff0c;形成多屏渲染的效果&#xff0c;做到真正的完全的画面同步&#xff0c;在主解码…

60、Flink CDC 入门介绍及Streaming ELT示例(同步Mysql数据库数据到Elasticsearch)-完整版

Flink 系列文章 一、Flink 专栏 Flink 专栏系统介绍某一知识点&#xff0c;并辅以具体的示例进行说明。 1、Flink 部署系列 本部分介绍Flink的部署、配置相关基础内容。 2、Flink基础系列 本部分介绍Flink 的基础部分&#xff0c;比如术语、架构、编程模型、编程指南、基本的…

Java项目:基于SSM框架实现的企业员工岗前培训管理系统(ssm+B/S架构+源码+数据库+毕业论文)

一、项目简介 本项目是一套ssm821基于ssm框架实现的企业员工岗前培训管理系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格…

智能巡检系统:企业管理创新的一个新方向

智能巡检系统是一个重要的工具&#xff0c;它可以帮助企业实现更高效、更准确和更安全的管理。在谈论智能巡检时&#xff0c;我们主要关注的是以下几个方面的创新和改进。 数据处理能力&#xff1a;智能巡检系统通过云端处理技术&#xff0c;可以实现大规模数据的快速处理和分析…

接口参数校验之路径变量:@PathVariable(二):多个路径变量校验

一、引言 在上一篇文章《接口参数校验之路径变量&#xff1a;PathVariable》中&#xff0c;我们深入探讨了Spring MVC框架中的一个重要特性——路径变量的使用和校验。文章详细阐述了如何通过PathVariable注解从请求URL中提取路径变量&#xff0c;并对单个路径变量进行合法性校…

贝锐蒲公英全新网页认证,保障企业访客无线网络安全

随着企业规模的不断扩大、人员的增长、无线终端数量/类型的增加&#xff0c;传统WiFi无线网络会暴露出越来越多的问题&#xff0c;导致无线网络管理困难。 比如&#xff1a;采用弱密码、安全防护不到位的默认设置、员工缺乏信息安全意识、未经授人员权访问无线网络…… 这些问…

Kafka(九)跨集群数据镜像

目录 1 跨集群镜像的应用场景1.1 区域集群和中心集群1.2 高可用(HA)和灾备(DR)1.3 监管与合规1.4 云迁移1.5 聚合边缘集群的数据 2 多集群架构2.1 星型架构2.2 双活架构2.2 主备架构2.2.1 如何实现Kafka集群的故障转移2.2.1.1 故障转移包括的内容1. 灾难恢复计划2. 非计划内的故…
最新文章