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

news2024/12/19 18:22:36

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


上接:【题解】—— 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


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-yaml语法

1.概念 在Springboot的项目中&#xff0c;配置文件有以下几种格式&#xff1a; Application.propertiesApplication.yamlApplication.yml 其中官方推荐我们使用yaml的格式(因为能表示的数据类型很多样) 2.基本语法 # yaml形式的配置文件# 普通的key-value&#xff08;分号之后…

windows环境下Grafana+loki+promtail入门级部署日志系统,收集Springboot(Slf4j+logback)项目日志

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 往期热门专栏回顾 专栏…

MyBatis操作数据库(XML方式)

MyBatis是一个持久层框架&#xff0c;和Spring没有任何关系&#xff0c;可以用来简化数据库的操作&#xff01; 创建工作&#xff1a; 创建Spring Boot工程&#xff0c;并导入MyBatis的起步依赖&#xff0c;Mysql的依赖等 配置数据 #配置数据库的连接字符串 spring:datasour…

ruoyi 图片等文件资源读取

老是忘&#xff0c;记录一下 ResourcesConfig 文件下 /** 本地文件上传路径 */ registry.addResourceHandler(Constants.RESOURCE_PREFIX "/**").addResourceLocations("file:" RuoYiConfig.getProfile() "/"); /*** 资源映射路径 前缀*/ …

C++使用工具进阶(LOG输出、堆栈跟踪、代码结构、code review)

0. 简介 对于C&#xff0c;无论是大学生还是算法工程师都是非常需要学习并使用的一门语言&#xff0c;而C不像python、rust一样简单好用。不单单是在嵌套复杂代码后的逻辑还是各种类和堆栈的管理&#xff0c;都是非常头疼的问题。一般来说对于LOG类很多都是使用GLOG、而堆栈跟…

STM32 (1)

1.基本信息 stm32是由ST公司生产的一种32位微控制器&#xff08;单片机&#xff09;。 1.1 各种型号 stm32是32位单片机的总称&#xff0c;有多种不同的系列。 32即用32个比特位表示一个地址&#xff0c;寻址范围&#xff1a;0x00000000 --0xffffffff (4GB) 1.2 存储密度 …

本地如何配置支付宝模拟支付场景并结合内网穿透实现公网环境调试开发?

文章目录 前言1. 下载当面付demo2. 修改配置文件3. 打包成web服务4. 局域网测试5. 内网穿透6. 测试公网访问7. 配置二级子域名8. 测试使用固定二级子域名访问 前言 在沙箱环境调试支付SDK的时候&#xff0c;往往沙箱环境部署在本地&#xff0c;局限性大&#xff0c;在沙箱环境…

[环境配置]ssh连接报错“kex_exchange_identification: read: Connection reset by peer”

已经被VScode ssh毒死好几次了&#xff0c;都是执行命令意外中断&#xff0c;然后又VSCode里连不上、本机Terminal也连不上了。。。 重启远程服务器&#xff0c;VSCode可以连上了&#xff0c; 系统ssh还是不行&#xff0c;报错“kex_exchange_identification: read: Connecti…

数字化转型对企业有什么意义

降本增效&#xff0c;提高生产力 数字化转型可以引入自动化和智能化技术、帮助企业优化流程、减少人工操作和错误&#xff0c;提高工作效率和生产力。例如&#xff0c;使用机器人流程自动化 (RPA) 可以自动执行重复性任务&#xff0c;使员工能够专注于更具价值的工作。除了通过…

YOLOv5独家原创改进:特征融合涨点篇 | 广义高效层聚合网络(GELAN) | YOLOv9

💡💡💡本文独家改进:即结合用梯度路径规划(CSPNet)和(ELAN)设计了一种广义的高效层聚合网络(GELAN),高效结合YOLOv5,实现涨点。 将GELAN添加在backbone和head处,提供多个yaml改进方法 💡💡💡在多个私有数据集和公开数据集VisDrone2019、PASCAL VOC实现…

5.测试教程 - 进阶篇

文章目录 1.按测试对像划分1.1**界面测试**1.2**可靠性测试**1.3**容错性测试**1.4**文档测试**1.5**兼容性测试**1.6**易用性测试**1.7**安装卸载测试**1.8**安全测试**1.9**性能测试**1.10**内存泄漏测试** 2.按是否查看代码划分2.1黑盒测试(Black-box Testing)2.2白盒测试(W…

获取properties二个键值对的值

配置文件&#xff1a; 将属性文件中的值赋给Java类的成员变量&#xff1a; 测试方法&#xff1a; GetMapping("/test1") public String test1(String key) {JSONObject jsonUrl JSONObject.parseObject("{"url"}");System.out.println(" …

计算机网络-网络安全(一)

1.网络安全威胁和漏洞类型&#xff1a; 窃听 假冒 重放 流量分析 破环完整 病毒 木马 诽谤 非授权访问 拒绝服务 漏洞&#xff1a;物理、软件、不兼容、其他等。 2.网络安全信息数据五大特征&#xff1a; 完整性&…

四川首例强生全视人工晶体在成都爱尔眼科医院成功植入

【2024年3月1日&#xff0c;成都】全国首批、四川首例强生全视TECNIS Symfony™ Toric IOL植入手术在成都爱尔眼科医院成功开展&#xff0c;手术由爱尔眼科四川省区白内障学组组长、成都爱尔眼科医院副院长巫雷教授执刀。TECNIS Symfony™ Toric IOL的成功运用&#xff0c;不仅…

第二十一周周报

文献阅读&#xff1a;Recent Advances of Monocular 2D and 3D Human Pose Estimation: A Deep Learning Perspective 摘要&#xff1a;在本文中&#xff0c;作者提供了一个全面的 2d到3d视角来解决单目人体姿态估计的问题。首先&#xff0c;全面总结了人体的二维和三维表征。…

思科网络设备监控

思科是 IT 行业的先驱之一&#xff0c;提供从交换机到刀片服务器的各种设备&#xff0c;以满足中小企业和企业的各种 IT 管理需求。管理充满思科的 IT 车间涉及许多管理挑战&#xff0c;例如监控可用性和性能、管理配置更改、存档防火墙日志、排除带宽问题等等&#xff0c;这需…

如何自学python

Python是一种高级编程语言,它具有简单易学、可读性强、可移植性好、功能丰富等优点,因此在许多领域都被广泛使用,如科学计算、数据分析、人工智能、Web开发、游戏开发等等。 Python具有丰富的标准库和第三方库,可以帮助程序员快速开发功能强大的应用程序。同时,Python也具…

2024.02.29作业

1. TCP模型 server #include "test.h"#define SER_IP "192.168.191.128" #define SER_PORT 9999int main(int argc, char const *argv[]) {int sfd -1;sfd socket(AF_INET, SOCK_STREAM, 0);if (-1 sfd){perror("socket error");return -1;…

六、继承(一)

1 继承的引入 以往我们想分别实现描述学生、老师的类&#xff0c;可能会这样子做&#xff1a; class Student {string _name;string _number;int _tel;int id;string _address;int _age; }; class Teacher {string _name;int _level;int _tel;int id;string _address;int _ag…

数据中台:数字中国战略关键技术实施

这里写目录标题 前言为何要建设数据中台数据中台建设痛点数据中台学习资料聚焦前沿&#xff0c;方法论体系更新与时俱进&#xff0c;紧跟时代热点深入6大行业&#xff0c;提炼实践精华大咖推荐&#xff0c;数字化转型必备案头书 前言 在数字中国这一国家战略的牵引下&#xff0…