【题解】—— LeetCode一周小结9


【题解】—— 每日一道题目栏


上接:【题解】—— LeetCode一周小结8

26.二叉搜索树的范围和

题目链接:938. 二叉搜索树的范围和

给定二叉搜索树的根结点 root,返回值位于范围 [low, high] 之间的所有结点的值的和。

示例 1:

在这里插入图片描述

输入:root = [10,5,15,3,7,null,18], low = 7, high = 15

输出:32

示例 2:
在这里插入图片描述

输入:root = [10,5,15,3,7,13,18,1,null,6], low = 6, high = 10

输出:23

提示:

树中节点数目在范围 [1, 2 * 104] 内

1 <= Node.val <= 105

1 <= low <= high <= 105

所有 Node.val 互不相同

题解:
方法:递归
        

/**
 * 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 {
    int low, high;
    int ans;
    public int rangeSumBST(TreeNode root, int _low, int _high) {
        low = _low; high = _high;
        dfs(root);
        return ans;
    }
    void dfs(TreeNode root) {
        if (root == null) return;
        dfs(root.left);
        if (low <= root.val && root.val <= high) ans += root.val;
        dfs(root.right);
    }
}

方法:迭代
        使用栈来模拟递归过程

class Solution {
    public int rangeSumBST(TreeNode root, int low, int high) {
        int ans = 0;
        Deque<TreeNode> d = new ArrayDeque<>();
        while (root != null || !d.isEmpty()) {
            while (root != null) {
                d.addLast(root);
                root = root.left;
            }
            root = d.pollLast();
            if (low <= root.val && root.val <= high) {
                ans += root.val;
            }
            root = root.right;
        }
        return ans;
    }
}

27.统计树中的合法路径数目

题目链接:2867. 统计树中的合法路径数目

给你一棵 n 个节点的无向树,节点编号为 1 到 n 。给你一个整数 n 和一个长度为 n - 1 的二维整数数组 edges ,其中 edges[i] = [ui, vi] 表示节点 ui 和 vi 在树中有一条边。

请你返回树中的 合法路径数目 。

如果在节点 a 到节点 b 之间 恰好有一个 节点的编号是质数,那么我们称路径 (a, b) 是 合法的 。

注意:

路径 (a, b) 指的是一条从节点 a 开始到节点 b 结束的一个节点序列,序列中的节点 互不相同 ,且相邻节点之间在树上有一条边。
路径 (a, b) 和路径 (b, a) 视为 同一条 路径,且只计入答案 一次 。

示例 1:

输入:n = 5, edges = [[1,2],[1,3],[2,4],[2,5]]

输出:4

解释:恰好有一个质数编号的节点路径有:

  • (1, 2) 因为路径 1 到 2 只包含一个质数 2 。
  • (1, 3) 因为路径 1 到 3 只包含一个质数 3 。
  • (1, 4) 因为路径 1 到 4 只包含一个质数 2 。
  • (2, 4) 因为路径 2 到 4 只包含一个质数 2 。

只有 4 条合法路径。

示例 2:

输入:n = 6, edges = [[1,2],[1,3],[2,4],[3,5],[3,6]]

输出:6

解释:恰好有一个质数编号的节点路径有:

  • (1, 2) 因为路径 1 到 2 只包含一个质数 2 。
  • (1, 3) 因为路径 1 到 3 只包含一个质数 3 。
  • (1, 4) 因为路径 1 到 4 只包含一个质数 2 。
  • (1, 6) 因为路径 1 到 6 只包含一个质数 3 。
  • (2, 4) 因为路径 2 到 4 只包含一个质数 2 。
  • (3, 6) 因为路径 3 到 6 只包含一个质数 3 。

只有 6 条合法路径。

提示:

1 <= n <= 105

edges.length == n - 1

edges[i].length == 2

1 <= ui, vi <= n

输入保证 edges 形成一棵合法的树。

题解:
方法:O(n) 线性做法
        计算从每个质数出发,经过不同路径到达非质数的路径总数。首先使用深度优先搜索遍历树的每个连通块,并将连通块中的节点数量保存在数组 size 中。然后对于每个质数节点,遍历其相连的非质数节点,根据每个非质数节点所在的连通块大小计算路径总数,并累加到答案中。

class Solution {
    private final static int MX = (int) 1e5;
    private final static boolean[] np = new boolean[MX + 1]; // 质数=false 非质数=true

    // 预处理出所有质数
    static {
        np[1] = true;
        for (int i = 2; i * i <= MX; i++) {
            if (!np[i]) {
                for (int j = i * i; j <= MX; j += i) {
                    np[j] = true;
                }
            }
        }
    }

    /**
     * 计算从每个质数出发,经过不同路径到达非质数的路径总数。
     * @param n 树的节点数
     * @param edges 树的边集合
     * @return 路径总数
     */
    public long countPaths(int n, int[][] edges) {
        // 构建树的邻接表
        List<Integer>[] g = new ArrayList[n + 1];
        Arrays.setAll(g, e -> new ArrayList<>());
        for (var e : edges) {
            int x = e[0], y = e[1];
            g[x].add(y);
            g[y].add(x);
        }

        long ans = 0; // 结果路径总数
        int[] size = new int[n + 1]; // 保存每个连通块的节点数量
        var nodes = new ArrayList<Integer>(); // 保存当前连通块的节点集合
        // 遍历每个质数
        for (int x = 1; x <= n; x++) {
            if (np[x]) { // 跳过非质数
                continue;
            }
            int sum = 0; // 记录所有非质数的节点数量
            // 遍历与当前质数相连的节点
            for (int y : g[x]) {
                if (!np[y]) { // 只考虑非质数节点
                    if (size[y] == 0) { // 若当前连通块尚未计算过
                        nodes.clear(); // 清空节点集合
                        dfs(y, -1, g, nodes); // 从当前非质数节点出发,深度优先遍历连通块,并将节点添加到集合中
                        // 更新当前连通块中每个节点的连通块大小
                        for (int z : nodes) {
                            size[z] = nodes.size();
                        }
                    }
                    // 计算从当前质数节点出发,经过不同路径到达非质数节点的路径总数
                    ans += (long) size[y] * sum;
                    sum += size[y]; // 更新所有非质数的节点数量
                }
            }
            ans += sum; // 将从当前质数节点出发的路径总数加入结果中
        }
        return ans; // 返回路径总数
    }

    /**
     * 深度优先搜索函数,用于遍历树的连通块并保存节点。
     * @param x 当前处理的节点
     * @param fa 当前节点的父节点
     * @param g 树的邻接表表示
     * @param nodes 保存当前连通块的节点集合
     */
    private void dfs(int x, int fa, List<Integer>[] g, List<Integer> nodes) {
        nodes.add(x); // 将当前节点加入节点集合
        // 遍历当前节点的邻居节点
        for (int y : g[x]) {
            if (y != fa && np[y]) { // 跳过父节点和质数节点
                dfs(y, x, g, nodes); // 递归遍历当前节点的邻居节点
            }
        }
    }
}


28.使二叉树所有路径值相等的最小代价

题目链接:2673. 使二叉树所有路径值相等的最小代价

给你一个整数 n 表示一棵 满二叉树 里面节点的数目,节点编号从 1 到 n 。根节点编号为 1 ,树中每个非叶子节点 i 都有两个孩子,分别是左孩子 2 * i 和右孩子 2 * i + 1 。

树中每个节点都有一个值,用下标从 0 开始、长度为 n 的整数数组 cost 表示,其中 cost[i] 是第 i + 1 个节点的值。每次操作,你可以将树中 任意 节点的值 增加 1 。你可以执行操作 任意 次。

你的目标是让根到每一个 叶子结点 的路径值相等。请你返回 最少 需要执行增加操作多少次。

注意:

满二叉树 指的是一棵树,它满足树中除了叶子节点外每个节点都恰好有 2 个子节点,且所有叶子节点距离根节点距离相同。
路径值 指的是路径上所有节点的值之和。

示例 1:
在这里插入图片描述

输入:n = 7, cost = [1,5,2,2,3,3,1]

输出:6

解释:我们执行以下的增加操作:

  • 将节点 4 的值增加一次。
  • 将节点 3 的值增加三次。
  • 将节点 7 的值增加两次。

从根到叶子的每一条路径值都为 9 。

总共增加次数为 1 + 3 + 2 = 6 。

这是最小的答案。

示例 2:

在这里插入图片描述

输入:n = 3, cost = [5,3,3]

输出:0

解释:两条路径已经有相等的路径值,所以不需要执行任何增加操作。

提示:

3 <= n <= 105

n + 1 是 2 的幂

cost.length == n

1 <= cost[i] <= 104

题解:
方法:贪心
        将二叉树中的每个非叶节点的两个子节点变为相同值所需的最小增量之和。从最后一个非叶节点开始,逐层向上计算。对于每个非叶节点,计算将两个子节点变为相同值所需的增量,并累加到结果中。然后将当前节点更新为其子节点中值较大的那个,以满足父节点的要求。

class Solution {
    /**
     * 计算将二叉树中的每个非叶节点的两个子节点变为相同值所需的最小增量之和。
     * @param n 二叉树的节点数
     * @param cost 二叉树中每个节点的值
     * @return 最小增量之和
     */
    public int minIncrements(int n, int[] cost) {
        int ans = 0; // 初始化最小增量之和为0
        for (int i = n / 2; i > 0; i--) { // 从最后一个非叶节点开始向上计算
            // 计算将两个子节点变为相同值所需的增量,累加到结果中
            ans += Math.abs(cost[i * 2 - 1] - cost[i * 2]);
            // 将当前节点更新为其子节点中值较大的那个,以满足父节点的要求
            cost[i - 1] += Math.max(cost[i * 2 - 1], cost[i * 2]);
        }
        return ans; // 返回最小增量之和
    }
}


29.统计可能的树根数目

题目链接:2581. 统计可能的树根数目

Alice 有一棵 n 个节点的树,节点编号为 0 到 n - 1 。树用一个长度为 n - 1 的二维整数数组 edges 表示,其中 edges[i] = [ai, bi] ,表示树中节点 ai 和 bi 之间有一条边。

Alice 想要 Bob 找到这棵树的根。她允许 Bob 对这棵树进行若干次 猜测 。每一次猜测,Bob 做如下事情:

选择两个 不相等 的整数 u 和 v ,且树中必须存在边 [u, v] 。
Bob 猜测树中 u 是 v 的 父节点 。
Bob 的猜测用二维整数数组 guesses 表示,其中 guesses[j] = [uj, vj] 表示 Bob 猜 uj 是 vj 的父节点。

Alice 非常懒,她不想逐个回答 Bob 的猜测,只告诉 Bob 这些猜测里面 至少 有 k 个猜测的结果为 true 。

给你二维整数数组 edges ,Bob 的所有猜测和整数 k ,请你返回可能成为树根的 节点数目 。如果没有这样的树,则返回 0。

示例 1:

在这里插入图片描述

输入:edges = [[0,1],[1,2],[1,3],[4,2]], guesses =
[[1,3],[0,1],[1,0],[2,4]], k = 3

输出:3

解释:

根为节点 0 ,正确的猜测为 [1,3], [0,1], [2,4]

根为节点 1 ,正确的猜测为 [1,3], [1,0], [2,4]

根为节点 2 ,正确的猜测为 [1,3], [1,0], [2,4]

根为节点 3 ,正确的猜测为 [1,0], [2,4]

根为节点 4 ,正确的猜测为 [1,3], [1,0]

节点 0 ,1 或 2 为根时,可以得到 3 个正确的猜测。

示例 2:

在这里插入图片描述

输入:edges = [[0,1],[1,2],[2,3],[3,4]], guesses =
[[1,0],[3,4],[2,1],[3,2]], k = 1

输出:5

解释:

根为节点 0 ,正确的猜测为 [3,4]

根为节点 1 ,正确的猜测为 [1,0], [3,4]

根为节点 2 ,正确的猜测为 [1,0], [2,1], [3,4]

根为节点 3 ,正确的猜测为 [1,0], [2,1], [3,2], [3,4]

根为节点 4 ,正确的猜测为 [1,0], [2,1], [3,2]

任何节点为根,都至少有 1 个正确的猜测。

提示:

edges.length == n - 1

2 <= n <= 105

1 <= guesses.length <= 105

0 <= ai, bi, uj, vj <= n - 1

ai != bi

uj != vj

edges 表示一棵有效的树。

guesses[j] 是树中的一条边。

guesses 是唯一的。

0 <= k <= guesses.length

题解:
方法:换根 DP

知识点:【图解】一张图秒懂换根 DP!

换根 DP
        首先通过深度优先搜索以根节点0为根的情况,计算每个节点为根时猜对的次数。然后对于每个节点,通过深度优先搜索重新确定根节点,并计算满足猜对次数的根节点个数。

class Solution {
    private List<Integer>[] g; // 邻接表表示的图
    private Set<Long> s = new HashSet<>(); // 哈希表存储猜测的结果
    private int k, ans, cnt0; // k: 猜对的最小次数;ans: 可能的根节点个数;cnt0: 以根节点为0时的猜对次数

    /**
     * 计算以哪些节点为根时,满足猜对的最小次数的根节点个数。
     * @param edges 二维数组表示边的关系
     * @param guesses 二维数组表示猜测的结果
     * @param k 猜对的最小次数
     * @return 满足猜对的最小次数的根节点个数
     */
    public int rootCount(int[][] edges, int[][] guesses, int k) {
        this.k = k; // 初始化猜对的最小次数
        g = new ArrayList[edges.length + 1]; // 初始化邻接表
        Arrays.setAll(g, i -> new ArrayList<>()); // 初始化每个顶点的邻接表
        for (int[] e : edges) { // 建图
            int x = e[0];
            int y = e[1];
            g[x].add(y);
            g[y].add(x);
        }

        for (int[] e : guesses) { // 将猜测的结果转换成哈希表存储
            s.add((long) e[0] << 32 | e[1]); // 将两个 4 字节 int 压缩成一个 8 字节 long
        }

        dfs(0, -1); // 以0为根进行dfs
        reroot(0, -1, cnt0); // 以每个节点为根进行dfs
        return ans; // 返回结果
    }

    /**
     * 以根节点为0进行深度优先搜索,计算每个节点为根时猜对的次数。
     * @param x 当前处理的节点
     * @param fa 当前节点的父节点
     */
    private void dfs(int x, int fa) {
        for (int y : g[x]) { // 遍历当前节点的相邻节点
            if (y != fa) { // 如果相邻节点不是父节点
                if (s.contains((long) x << 32 | y)) { // 如果当前边是猜对的
                    cnt0++; // 增加以0为根时猜对的次数
                }
                dfs(y, x); // 递归处理相邻节点
            }
        }
    }

    /**
     * 以每个节点为根进行深度优先搜索,计算满足猜对次数的根节点个数。
     * @param x 当前处理的节点
     * @param fa 当前节点的父节点
     * @param cnt 以当前节点为根时猜对的次数
     */
    private void reroot(int x, int fa, int cnt) {
        if (cnt >= k) { // 如果以当前节点为根时猜对的次数大于等于要求的最小次数k
            ans++; // 增加满足条件的根节点个数
        }
        for (int y : g[x]) { // 遍历当前节点的相邻节点
            if (y != fa) { // 如果相邻节点不是父节点
                int c = cnt; // 记录以当前节点为根时猜对的次数
                if (s.contains((long) x << 32 | y)) c--; // 如果原来是对的,现在是错的
                if (s.contains((long) y << 32 | x)) c++; // 如果原来是错的,现在是对的
                reroot(y, x, c); // 递归处理相邻节点
            }
        }
    }
}


2024.3

1.检查数组是否存在有效划分

题目链接:2369. 检查数组是否存在有效划分

给你一个下标从 0 开始的整数数组 nums ,你必须将数组划分为一个或多个 连续 子数组。

如果获得的这些子数组中每个都能满足下述条件 之一 ,则可以称其为数组的一种 有效 划分:

子数组 恰 由 2 个相等元素组成,例如,子数组 [2,2] 。
子数组 恰 由 3 个相等元素组成,例如,子数组 [4,4,4] 。
子数组 恰 由 3 个连续递增元素组成,并且相邻元素之间的差值为 1 。例如,子数组 [3,4,5] ,但是子数组 [1,3,5] 不符合要求。
如果数组 至少 存在一种有效划分,返回 true ,否则,返回 false 。

示例 1:

输入:nums = [4,4,4,5,6]

输出:true

解释:数组可以划分成子数组 [4,4] 和 [4,5,6] 。

这是一种有效划分,所以返回 true 。

示例 2:

输入:nums = [1,1,1,2]

输出:false

解释:该数组不存在有效划分。

提示:

2 <= nums.length <= 105

1 <= nums[i] <= 106

题解:
方法:动态规划
        使用f[i]表示前i个元素是否可以构成连续子序列。初始化f[0]=true,表示前0个元素肯定可以构成连续子序列。然后,遍历数组中的元素,根据当前元素与前一个元素的关系以及前两个元素的关系,更新f[i]的值。最终返回f[n],表示前n个元素是否可以构成连续子序列。

class Solution {
    /**
     * 判断数组是否可以分成若干连续子序列,每个子序列长度至少为3,且相邻元素之间的差值为1。
     * @param nums 给定的整数数组
     * @return 若数组可以分成若干连续子序列,返回true;否则,返回false
     */
    public boolean validPartition(int[] nums) {
        int n = nums.length; // 数组的长度
        boolean[] f = new boolean[n + 1]; // 动态规划数组,f[i]表示前i个元素是否可以构成连续子序列
        f[0] = true; // 初始条件,前0个元素肯定可以构成连续子序列
        for (int i = 1; i < n; i++) {
            if (f[i - 1] && nums[i] == nums[i - 1] || // 如果前i-1个元素可以构成连续子序列,并且当前元素与前一个元素相同
                i > 1 && f[i - 2] && (nums[i] == nums[i - 1] && nums[i] == nums[i - 2] || // 或者前i-2个元素可以构成连续子序列,并且当前元素与前一个元素相同,并且当前元素与前两个元素相同
                                      nums[i] == nums[i - 1] + 1 && nums[i] == nums[i - 2] + 2)) { // 或者当前元素与前一个元素相差1,与前两个元素相差2
                f[i + 1] = true; // 则前i个元素可以构成连续子序列
            }
        }
        return f[n]; // 返回前n个元素是否可以构成连续子序列
    }
}


2.受限条件下可到达节点的数目

题目链接:2368. 受限条件下可到达节点的数目

现有一棵由 n 个节点组成的无向树,节点编号从 0 到 n - 1 ,共有 n - 1 条边。

给你一个二维整数数组 edges ,长度为 n - 1 ,其中 edges[i] = [ai, bi] 表示树中节点 ai 和 bi 之间存在一条边。另给你一个整数数组 restricted 表示 受限 节点。

在不访问受限节点的前提下,返回你可以从节点 0 到达的 最多 节点数目。

注意,节点 0 不 会标记为受限节点。

示例 1:

在这里插入图片描述

输入:n = 7, edges = [[0,1],[1,2],[3,1],[4,0],[0,5],[5,6]], restricted =
[4,5]

输出:4

解释:上图所示正是这棵树。

在不访问受限节点的前提下,只有节点 [0,1,2,3] 可以从节点 0 到达。

示例 2:

在这里插入图片描述

输入:n = 7, edges = [[0,1],[0,2],[0,5],[0,4],[3,2],[6,5]], restricted =
[4,2,1]

输出:3

解释:上图所示正是这棵树。

在不访问受限节点的前提下,只有节点 [0,5,6] 可以从节点 0 到达。

提示:

2 <= n <= 15

edges.length == n - 1

edges[i].length == 2

0 <= ai, bi < n

ai != bi

edges 表示一棵有效的树

1 <= restricted.length < n

1 <= restricted[i] < n

restricted 中的所有值 互不相同

题解:
方法:树上 DFS
        使用深度优先搜索来解决问题。首先,将受限制的节点转换成布尔数组,然后构建图的邻接表表示。接着,对每个节点进行深度优先搜索,计算以该节点为起点可以到达的节点数。最终返回以节点 0 为起点可以到达的节点数。

class Solution {
    /**
     * 计算在移除若干受限制的边之后,从节点 0 开始可以到达的节点数。
     * @param n 图中节点的数量
     * @param edges 图中的边
     * @param restricted 受限制的节点数组
     * @return 从节点 0 开始可以到达的节点数
     */
    public int reachableNodes(int n, int[][] edges, int[] restricted) {
        // 将受限制的节点转换成一个布尔数组,方便进行判断
        boolean[] isRestricted = new boolean[n];
        for (int x : restricted) {
            isRestricted[x] = true;
        }
        // 构建图的邻接表表示
        List<Integer>[] g = new ArrayList[n];
        Arrays.setAll(g, i -> new ArrayList<>());
        // 遍历所有边,如果两个节点都不受限制,则在邻接表中添加边
        for (int[] e : edges) {
            int x = e[0], y = e[1];
            if (!isRestricted[x] && !isRestricted[y]) {
                g[x].add(y);
                g[y].add(x);
            }
        }
        // 进行深度优先搜索,计算可以到达的节点数
        return dfs(0, -1, g);
    }

    /**
     * 深度优先搜索函数,计算以节点 x 为起点可以到达的节点数。
     * @param x 当前处理的节点
     * @param fa x 的父节点
     * @param g 图的邻接表表示
     * @return 以节点 x 为起点可以到达的节点数
     */
    private int dfs(int x, int fa, List<Integer>[] g) {
        int cnt = 1; // 从节点 x 出发,可以到达它自己
        for (int y : g[x]) { // 遍历节点 x 的所有邻居节点
            if (y != fa) { // 避免回到父节点,防止形成环
                cnt += dfs(y, x, g); // 递归计算从邻居节点 y 出发可以到达的节点数
            }
        }
        return cnt; // 返回以节点 x 为起点可以到达的节点数
    }
}


3.用队列实现栈

题目链接:225. 用队列实现栈

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。

实现 MyStack 类:

void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

注意:

你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。
你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

示例:

输入:

[“MyStack”, “push”, “push”, “top”, “pop”, “empty”]

[[], [1], [2], [], [], []]

输出:

[null, null, null, 2, 2, false]

解释:

MyStack myStack = new MyStack();

myStack.push(1);

myStack.push(2);

myStack.top(); // 返回 2

myStack.pop(); // 返回 2

myStack.empty(); // 返回 False

提示:

1 <= x <= 9

最多调用100 次 push、pop、top 和 empty

每次调用 pop 和 top 都保证栈不为空

题解:
知识:用队列实现栈

方法:两个队列实现栈的操作
        主要思路是将元素压入栈时,先将元素存入辅助队列,然后将主队列中的元素全部移到辅助队列,最后交换主队列和辅助队列。这样能够保证每次入栈的元素都位于主队列的队首,从而实现栈的后进先出特性。

import java.util.LinkedList;
import java.util.Queue;

class MyStack {
    Queue<Integer> queue1; // 主队列,用于存储栈中的元素
    Queue<Integer> queue2; // 辅助队列,用于辅助元素入栈操作

    /** Initialize your data structure here. */
    public MyStack() {
        queue1 = new LinkedList<Integer>(); // 初始化主队列
        queue2 = new LinkedList<Integer>(); // 初始化辅助队列
    }
    
    /** Push element x onto stack. */
    public void push(int x) {
        queue2.offer(x); // 将新元素入辅助队列
        // 将主队列中的所有元素依次出队并入辅助队列,确保新元素位于队列头部
        while (!queue1.isEmpty()) {
            queue2.offer(queue1.poll());
        }
        // 交换主队列和辅助队列,确保主队列始终为非空队列
        Queue<Integer> temp = queue1;
        queue1 = queue2;
        queue2 = temp;
    }
    
    /** Removes the element on top of the stack and returns that element. */
    public int pop() {
        return queue1.poll(); // 从主队列中出队即可
    }
    
    /** Get the top element. */
    public int top() {
        return queue1.peek(); // 返回主队列的队首元素,即栈顶元素
    }
    
    /** Returns whether the stack is empty. */
    public boolean empty() {
        return queue1.isEmpty(); // 判断主队列是否为空即可
    }
}

方法:一个队列实现栈的操作
        利用了队列先进先出(FIFO)的特性来实现栈的后进先出(LIFO)的操作。在每次入栈时,先将新元素入队,然后将队列中之前的元素依次出队再入队,以保证新入队的元素始终位于队首,从而实现栈的特性。

import java.util.LinkedList;
import java.util.Queue;

class MyStack {
    Queue<Integer> queue; // 使用队列实现栈
    /** Initialize your data structure here. */
    public MyStack() {
        queue = new LinkedList<Integer>(); // 初始化队列
    }
    
    /** Push element x onto stack. */
    public void push(int x) {
        int n = queue.size(); // 获取当前队列的大小
        queue.offer(x); // 将元素入队
        // 将之前的元素逐个出队再入队,使得新入队的元素位于队首,实现栈的特性
        for (int i = 0; i < n; i++) {
            queue.offer(queue.poll());
        }
    }
    
    /** Removes the element on top of the stack and returns that element. */
    public int pop() {
        return queue.poll(); // 直接出队即可
    }
    
    /** Get the top element. */
    public int top() {
        return queue.peek(); // 获取队首元素,即栈顶元素
    }
    
    /** Returns whether the stack is empty. */
    public boolean empty() {
        return queue.isEmpty(); // 判断队列是否为空
    }
}


下接:【题解】—— LeetCode一周小结10


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

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

相关文章

Stable Diffusion——Animate Diff一键AI图像转视频

前言 AnimateDiff 是一个实用框架&#xff0c;可以对文本生成图像模型进行动画处理&#xff0c;无需进行特定模型调整&#xff0c;即可为大多数现有的个性化文本转图像模型提供动画化能力。而Animatediff 已更新至 2.0 版本和3.0两个版本&#xff0c;相较于 1.0 版本&#xff…

MySQL 多表查询 连接查询 自连接

介绍 自连接查询&#xff0c;可以是内连接查询&#xff0c;也可以是外连接查询&#xff0c;一句话自己连接自己&#xff0c;一个表当作两个表进行连接。 语法 SELECT 字段列表 FROM 表A 别名A JOIN 表A 别名B ON 条件两个表A说明是同一张表&#xff0c;但是别名不同 案例…

【ue5】滑铲系统蓝图笔记

大致逻辑如下&#xff1a; 一、导入动画 滑铲蹲待机蹲行走 导入到文件夹中 可以右键设置颜色&#xff0c;便于区分。 二、调整动画 1.启动根运动 启动根运动后&#xff0c;人物才可以位移&#xff0c;不然只能在原地。 打开动画序列&#xff0c;勾选启用根运动Enabled…

好书推荐丨细说PyTorch深度学习:理论、算法、模型与编程实现

文章目录 写在前面深度学习推荐图书内容简介作者简介 推荐理由粉丝福利写在最后 写在前面 本期博主给大家推荐一本深度学习的全新正版书籍&#xff0c;感兴趣的小伙伴快来看看吧~ 深度学习 深度学习是机器学习的一个分支&#xff0c;它模仿人脑神经网络的工作原理进行复杂的…

网络协议栈--应用层--HTTPS协议

目录 一、HTTPS协议原理1.1 HTTPS协议是什么&#xff1f;1.2 概念准备1.2.1 什么是“加密”&#xff1f;1.2.2 为什么要加密&#xff1f;1.2.3 常见的加密方式1.2.3.1 对称加密1.2.3.2 非对称加密 1.2.4 数据摘要&&数据指纹1.2.5 数字签名1.2.6 理解链-承上启下 1.3 HT…

掘根宝典之C语言字符串输入函数(gets(),fgets(),get_s())

字符串输入前的注意事项 如果想把一个字符串读入程序&#xff0c;首先必须预留该字符串的空间&#xff0c;然后用输入函数获取该字符串 这意味着必须要为字符串分配足够的空间。 不要指望计算机在读取字符串时顺便计算它的长度&#xff0c;然后再分配空间(计算机不会这样做&a…

软件实例,佳易王账单账本记账汇总统计管理系统软件教程

软件实例&#xff0c;佳易王账单账本记账汇总统计管理系统软件教程 一、前言 以下软件程序教程 以 佳易王账单记账汇总统计管理系统软件V17.0为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 账单可以记录 1、收入明细 2、支出明细 3、客户…

信息安全是什么

信息安全&#xff0c;也称为信息安全或数据安全&#xff0c;是防止未经授权的访问、更改、中断和破坏信息。 信息安全本身包括的范围很大&#xff0c;大到国家军事政治等机密安全&#xff0c;小范围的当然还包括如防范商业企业机密泄露&#xff0c;防范青少年对不良信息的浏览…

Excel中筛选合并单元格后,只显示第一行怎么办?

Excel中筛选合并单元格后,只显示第一行怎么办? 参考链接:https://baijiahao.baidu.com/s?id=1736773058549439034&wfr=spider&for=pc 我们日常的Excel数据在展示的时候为了数据的清晰和美观往往部分相同的单元格进行合并,但是合并之后在筛选时会发现结果会显示异…

Vanna-ai -基于RAG的TextToSql实现方案

官方连接&#xff1a;Vanna.AI - Personalized AI SQL Agent 1.背景 基于大模型的TextToSql的关键为给大模型提供正确有效的数据库信息及问题&#xff0c;以提升大模型生成sql的正确率。database_info question形成prompt&#xff0c;但是实际中通常会遇到一个问题&#xff…

【前端】Vite打包页面简单部署到GitHub上

创建仓库---->上传代码---->设置 注意点已经打上箭头,代码我传到的是test分支 vite打包的配置如图&#xff0c;base是仓库名称&#xff0c;docs是build后生成的打包目录。 上传到GitHub就自动部署了 访问就是第一张图里的一串地址&#xff0c;这种方式比较方便吧

Claude 3 模型列表

claude-3-opus-20240229 这个模型就好

Midjourney入门:AI绘画真的能替代人类的丹青妙笔吗?

名人说&#xff1a;一花独放不是春&#xff0c;百花齐放花满园。——《增广贤文》 作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、简要介绍1、Midjourney2、使用方法 二、绘画1、动物类2、风景类3、动漫类4、艺…

CNAN知识图谱辅助推荐系统

CNAN知识图谱辅助推荐系统 文章介绍了一个基于KG的推荐系统模型&#xff0c;代码也已开源&#xff0c;可以看出主要follow了KGNN-LS 。算法流程大致如下&#xff1a; 1. 算法介绍 算法除去attention机制外&#xff0c;主要的思想在于&#xff1a;user由交互过的item来表示、i…

VMvare安装17安装centos8教程

阿里镜像站&#xff1a;https://mirrors.aliyun.com/centos centos-8-isos-x86_64安装包下载_开源镜像站-阿里云 https://mirrors.aliyun.com/centos/8/isos/x86_64/CentOS-8.5.2111-x86_64-dvd1.iso 将上面的链接复制到迅雷进行高速下载 vmvare安装配置教程安装教程 CentO…

Vue3 五天速成

文章目录 day 11. 创建vue3工程3. 响应式数据4. 计算属性 day 25. watch 监视6. watchEffect7. 标签的ref属性 day 38. 回顾TS中的接口_泛型_自定义类型9. props的使用10. 生命周期11. 自定义Hooks12. 路由 基本切换效果13. 路由 两个注意点14. 路由 路由器的工作模式15. 路由 …

【C++】类和对象终篇

个人主页 &#xff1a; zxctscl 文章封面来自&#xff1a;艺术家–贤海林 如有转载请先通知 文章目录 1. 前言2. 友元2.1 友元函数2.2 友元类 3. 内部类4. 匿名对象5. 拷贝对象时的一些编译器优化6. 再次理解类和对象 1. 前言 在上一篇博客中提到了类和对象中的构造函数与stat…

网盘拉新平台,如何授权对接“星子助推”?

找到“星子助推”&#xff1a;首先&#xff0c;找到“星子助推”这个授权渠道。他们是网盘服务提供商的合作伙伴&#xff0c;为你提供机会。注册并申请授权&#xff1a;在“星子助推”的平台上注册&#xff0c;并同时申请授权。填写邀请码8x25k&#xff0c;提交申请。获得授权并…

云服务器2核4G能支持多少人同时访问?2核4G5M并发量评测

腾讯云轻量应用服务器2核4G5M配置一年优惠价165元、252元15个月、三年756元&#xff0c;100%CPU性能&#xff0c;5M带宽下载速度640KB/秒&#xff0c;60GB SSD系统盘&#xff0c;月流量500GB&#xff0c;折合每天16.6GB流量&#xff0c;超出月流量包的流量按照0.8元每GB的价格支…