LeetCode 周赛 345(2023/05/14)体验一题多解的算法之美

news2024/10/6 15:57:50

本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问。

  • 往期回顾:LeetCode 双周赛第 104 场 · 流水的动态规划,铁打的结构化思考

周赛概览

T1. 找出转圈游戏输家(Easy)

  • 标签:模拟、计数

T2. 相邻值的按位异或(Medium)

  • 标签:模拟、数学、构造

T3. 矩阵中移动的最大次数(Medium)

  • 标签:图、BFS、DFS、动态规划

T4. 统计完全连通分量的数量(Medium)

  • 标签:图、BFS、DFS、并查集

T1. 找出转圈游戏输家(Easy)

https://leetcode.cn/problems/find-the-losers-of-the-circular-game/

题解(模拟)

简单模拟题。

使用标记数组标记接触到球的玩家,再根据标记数组输出结果:

class Solution {
    fun circularGameLosers(n: Int, k: Int): IntArray {
        val visit = BooleanArray(n)
        var i = 0
        var j = 1
        var cnt = n
        while (!visit[i]) {
            visit[i] = true
            i = (i + j++ * k) % n
            cnt--
        }
        val ret = IntArray(cnt)
        var k = 0
        for (i in visit.indices) {
            if(!visit[i]) ret[k++] = i + 1
        }
        return ret
    }
}

复杂度分析:

  • 时间复杂度: O ( n ) O(n) O(n) 每位玩家最多标记一次和检查一次;
  • 空间复杂度: O ( n ) O(n) O(n) 标记数组空间。

T2. 相邻值的按位异或(Medium)

https://leetcode.cn/problems/neighboring-bitwise-xor/

预备知识

记 ⊕ 为异或运算,异或运算满足以下性质:

  • 基本性质:x ⊕ y = 0
  • 交换律:x ⊕ y = y ⊕ x
  • 结合律:(x ⊕ y) ⊕ z = x ⊕ (y ⊕ z)
  • 自反律:x ⊕ y ⊕ y = x

题解一(模拟)

由于每一位 derived[i] 可以由 original[i] ⊕ original[i + 1] 获得,我们可以令原始的 original[0] 为 0,再按顺序递推到 original[n](循环数组),最后再检查 original[0] 和 original[n] 是否相同。如果不同,说明 derived 数组是不可构造的。

class Solution {
    fun doesValidArrayExist(derived: IntArray): Boolean {
        var pre = 0
        for ((i,d) in derived.withIndex()) {
            if (d == 1) pre = pre xor 1
        }
        return pre == 0
    }
}

复杂度分析:

  • 时间复杂度: O ( n ) O(n) O(n) 其中 n 为 derived 数组的长度;
  • 空间复杂度:仅使用常量级别空间。

题解二(数学)

继续挖掘问题的数学性质:

  • 题目要求: d e r i v e d [ i ] = o r i g i n a l [ i ] ⊕ o r i g i n a l [ i + 1 ] derived[i] = original[i] ⊕ original[i + 1] derived[i]=original[i]original[i+1]
  • 根据自反律(两边异或 original[i]): o r i g i n a l [ i + 1 ] = d e r i v e d [ i ] ⊕ o r i g i n a l [ i ] original[i + 1] = derived[i] ⊕ original[i] original[i+1]=derived[i]original[i] o r i g i n a l [ i + 2 ] = d e r i v e d [ i + 1 ] ⊕ o r i g i n a l [ i + 1 ] original[i + 2] = derived[i + 1] ⊕ original[i + 1] original[i+2]=derived[i+1]original[i+1]
  • 根据递推关系有 o r i g i n a l [ n − 1 ] = d e r i v e d [ n − 2 ] ⊕ d e r i v e d [ n − 1 ] … d e r i v e d [ 0 ] ⊕ o r i g i n a l [ 0 ] original[n - 1] = derived[n - 2] ⊕ derived[n - 1]… derived[0] ⊕ original[0] original[n1]=derived[n2]derived[n1]derived[0]original[0]
  • 题目要求: o r i g i n a l [ 0 ] ⊕ o r i g i n a l [ n − 1 ] = d e r i v e d [ n − 1 ] original[0] ⊕ original[n - 1] = derived[n-1] original[0]original[n1]=derived[n1]
  • 联合两式: o r i g i n a l [ 0 ] = o r i g i n a l [ 0 ] ⊕ d e r i v e d [ n − 1 ] ⊕ d e r i v e d [ n − 1 ] … d e r i v e d [ 0 ] ⊕ o r i g i n a l [ 0 ] original[0] = original[0] ⊕ derived[n-1] ⊕ derived[n - 1]… derived[0] ⊕ original[0] original[0]=original[0]derived[n1]derived[n1]derived[0]original[0],即 0 = d e r i v e d [ n − 1 ] ⊕ d e r i v e d [ n − 1 ] … d e r i v e d [ 0 ] 0 = derived[n-1] ⊕ derived[n - 1]… derived[0] 0=derived[n1]derived[n1]derived[0]

根据结论公式模拟即可:

class Solution {
    fun doesValidArrayExist(derived: IntArray): Boolean {
        // return derived.fold(0) {acc, e -> acc xor e} == 0
        return derived.reduce {acc, e -> acc xor e} == 0
    }
}

复杂度分析:

  • 时间复杂度: O ( n ) O(n) O(n) 其中 n 为 derived 数组的长度;
  • 空间复杂度:仅使用常量级别空间。

T3. 矩阵中移动的最大次数(Medium)

https://leetcode.cn/problems/maximum-number-of-moves-in-a-grid/

题目描述

给你一个下标从 0 开始、大小为 m x n 的矩阵 grid ,矩阵由若干  整数组成。

你可以从矩阵第一列中的 任一 单元格出发,按以下方式遍历 grid :

  • 从单元格 (row, col) 可以移动到 (row - 1, col + 1)(row, col + 1) 和 (row + 1, col + 1) 三个单元格中任一满足值 严格 大于当前单元格的单元格。

返回你在矩阵中能够 移动 的 最大 次数。

示例 1:

输入:grid = [[2,4,3,5],[5,4,9,3],[3,4,2,11],[10,9,13,15]]
输出:3
解释:可以从单元格 (0, 0) 开始并且按下面的路径移动:
- (0, 0) -> (0, 1).
- (0, 1) -> (1, 2).
- (1, 2) -> (2, 3).
可以证明这是能够移动的最大次数。

示例 2:

输入:grid = [[3,2,4],[2,1,9],[1,1,7]]
输出:0
解释:从第一列的任一单元格开始都无法移动。

提示:

  • m == grid.length
  • n == grid[i].length
  • 2 <= m, n <= 1000
  • 4 <= m * n <= 105
  • 1 <= grid[i][j] <= 106

问题结构化

1、概括问题目标

计算可移动的最大次数,也可以理解为可访问距离 - 1。

2、分析问题要件

在每次移动操作中,可以移动到右边一列的最近三行位置(i-1, i, j+1)且要求数字严格大于当前位置。

3、提高抽象程度

  • 子问题:我们发现每次移动后,可移动次数就是在新位置可移动次数 + 1,这是一个与原问题相似但规模更小的子问题;
  • 是否为决策问题?由于每次移动最多有三个位置选择,因此这是决策问题。

4、具体化解决手段

  • 手段 1(记忆化递归):定义 dfs(i, j) 表示从 grid[i][j] 开始的最大移动次数,那么有 dfs(i, j)= mas{dfs(i-1, j+1), dfs(i, j+1), dfs(i+1, j+1)};
  • 手段 2(递推):在记忆化递归中我们是在「归」的过程中合并子问题的解,由于递归的方向是验证矩阵从上到下,从左到右的,我们可以消除「递」的过程而只保留「归」的过程,将递归转换为递推;
  • 手段 3(BFS):由于可移动次数取决于最多可以移动到的列号,我们可以用 BFS / DFS 搜索最远可以访问的列号。

题解一(记忆化递归)

根据「手段 1」模拟即可:

  • 递归函数:dfs(i, j)= mas{dfs(i-1, j+1), dfs(i, j+1), dfs(i+1, j+1)}
  • 起始状态:dfs(i, 0)
  • 边界条件:dfs(i, j) = 0
class Solution {

    val directions = arrayOf(intArrayOf(-1, 1), intArrayOf(0, 1), intArrayOf(1, 1)) // 右上、右、右下

    private val memo = HashMap<Int, Int>()
    private val U = 1001

    fun maxMoves(grid: Array<IntArray>): Int {
        var ret = 0
        for (i in 0 until grid.size) {
            ret = Math.max(ret, dfs(grid, i, 0))
        }
        return ret - 1
    }

    private fun dfs(grid: Array<IntArray>, i: Int, j: Int): Int {
        val n = grid.size
        val m = grid[0].size
        val key = i * U + j
        if (memo.contains(key)) return memo[key]!!
        // 枚举选项
        var maxChoice = 0
        for (direction in directions) {
            val newI = i + direction[0]
            val newJ = j + direction[1]
            if (newI < 0 || newI >= n || newJ < 0 || newJ >= m || grid[i][j] >= grid[newI][newJ]) continue
            maxChoice = Math.max(maxChoice, dfs(grid, newI, newJ))
        }
        memo[key] = maxChoice + 1
        return maxChoice + 1
    }
}

复杂度分析:

  • 时间复杂度: O ( n m ) O(nm) O(nm) 总共有 nm 个子问题,每个子问题枚举 3 个选项时间复杂度是 O(1);
  • 空间复杂度: O ( n m ) O(nm) O(nm) 备忘录空间。

题解二(递推)

消除「递」的过程而只保留「归」的过程,将递归转换为递推:

class Solution {
    fun maxMoves(grid: Array<IntArray>): Int {
        val n = grid.size
        val m = grid[0].size
        val step = Array(n) { IntArray(m) }
        for (i in 0 until n) step[i][0] = 1
        var ret = 0
        // 按列遍历
        for(j in 1 until m) {
            for(i in 0 until n) {
                for(k in Math.max(0, i - 1) .. Math.min(n - 1,i + 1)) {
                    if (step[k][j - 1] > 0 && grid[i][j] > grid[k][j - 1]) step[i][j] = Math.max(step[i][j], step[k][j - 1] + 1)
                }
                ret = Math.max(ret, step[i][j])
            }
        }
        return Math.max(ret - 1, 0)
    }
}

另外,我们也可以用滚动数组优化空间:

class Solution {
    fun maxMoves(grid: Array<IntArray>): Int {
        val n = grid.size
        val m = grid[0].size
        var step = IntArray(n) { 1 }
        var ret = 0
        // 按列遍历
        for(j in 1 until m) {
            val newStep = IntArray(n) { 0 } // 不能直接在 step 数组上修改
            for(i in 0 until n) {
                for(k in Math.max(0, i - 1) .. Math.min(n - 1,i + 1)) {
                    if (step[k] > 0 && grid[i][j] > grid[k][j - 1]) newStep[i] = Math.max(newStep[i], step[k] + 1)
                }
                ret = Math.max(ret, newStep[i])
            }
            step = newStep
        }
        return Math.max(ret - 1, 0)
    }
}

复杂度分析:

  • 时间复杂度: O ( n m ) O(nm) O(nm)
  • 空间复杂度: O ( n ) O(n) O(n)

题解三(BFS)

按照广度优先搜索,使用队列维护可以访问的节点,再使用该节点探测下一层可到达的位置并入队。

class Solution {
    fun maxMoves(grid: Array<IntArray>): Int {
        val n = grid.size
        val m = grid[0].size
        // 行号
        var queue = LinkedList<Int>()
        for (i in 0 until n) {
            queue.offer(i)
        }
        // 访问标记
        val visit = IntArray(n) { -1 }
        // 枚举列
        for (j in 0 until m - 1) {
            val newQueue = LinkedList<Int>() // 不能直接在 step 数组上修改
            for (i in queue) {
                for (k in Math.max(0, i - 1)..Math.min(n - 1, i + 1)) {
                    if (visit[k] < j && grid[k][j + 1] > grid[i][j]) {
                        newQueue.offer(k)
                        visit[k] = j
                    }
                }
            }
            queue = newQueue
            if (queue.isEmpty()) return j
        }
        return m - 1
    }
}

复杂度分析:

  • 时间复杂度: O ( n m ) O(nm) O(nm)
  • 空间复杂度: O ( n ) O(n) O(n)

相似问题:

  • 62. 不同路径
  • 63. 不同路径 II

T4. 统计完全连通分量的数量(Medium)

https://leetcode.cn/problems/count-the-number-of-complete-components/

问题描述

给你一个整数 n 。现有一个包含 n 个顶点的 无向 图,顶点按从 0 到 n - 1 编号。给你一个二维整数数组 edges 其中 edges[i] = [ai, bi] 表示顶点 ai 和 bi 之间存在一条 无向 边。

返回图中 完全连通分量 的数量。

如果在子图中任意两个顶点之间都存在路径,并且子图中没有任何一个顶点与子图外部的顶点共享边,则称其为 连通分量 。

如果连通分量中每对节点之间都存在一条边,则称其为 完全连通分量 。

示例 1:

输入:n = 6, edges = [[0,1],[0,2],[1,2],[3,4]]
输出:3
解释:如上图所示,可以看到此图所有分量都是完全连通分量。

示例 2:

输入:n = 6, edges = [[0,1],[0,2],[1,2],[3,4],[3,5]]
输出:1
解释:包含节点 0、1 和 2 的分量是完全连通分量,因为每对节点之间都存在一条边。
包含节点 3 、4 和 5 的分量不是完全连通分量,因为节点 4 和 5 之间不存在边。
因此,在图中完全连接分量的数量是 1 。

提示:

  • 1 <= n <= 50
  • 0 <= edges.length <= n * (n - 1) / 2
  • edges[i].length == 2
  • 0 <= ai, bi <= n - 1
  • ai != bi
  • 不存在重复的边

预备知识 - 完全图

完全图中每对不同的顶点之间都恰连有一条边相连,n 个节点的完全图有 n*(n − 1) / 2 条边。

问题分析

这道题是比较直接的岛屿 / 连通分量问题,我们直接跑 DFS / BFS / 并查集,计算每个连通分量的节点数和边数是否平衡。

如果连通分量是完全图,那么节点数 v 和边数 e 满足 e == v * (v - 2) / 2

题解一(DFS)

枚举每个节点跑 DFS,统计相同连通分量的节点数 v 和节点数 e,由于在遍历的时候,同一条边会在两个节点上重复统计,所以判断连通分量是否为完全图的公式调整为 e == v * (v - 2)。

class Solution {
    fun countCompleteComponents(n: Int, edges: Array<IntArray>): Int {
        // 建图(邻接表)
        val graph = Array(n) { mutableListOf<Int>() }
        for (edge in edges) {
            graph[edge[0]].add(edge[1])
            graph[edge[1]].add(edge[0]) // 无向边
        }
        // 标记数组
        val visit = BooleanArray(n)
        // 枚举
        var ret = 0
        for (i in 0 until n) {
            if (visit[i]) continue
            val cnt = IntArray(2) // v, e
            dfs(graph, visit, i, cnt)
            if (cnt[1] == cnt[0] * (cnt[0] - 1)) ret++
        }
        return ret
    }

    private fun dfs(graph: Array<out List<Int>>, visit: BooleanArray, i: Int, cnt: IntArray) {
        visit[i] = true
        cnt[0] += 1 // 增加节点
        cnt[1] += graph[i].size // 增加边(会统计两次)
        for (to in graph[i]) {
            if (!visit[to]) dfs(graph, visit, to, cnt)
        }
    }
}

复杂度分析:

  • 时间复杂度: O ( n + m ) O(n + m) O(n+m) 其中 n 为节点数,m 为 edges 的长度;
  • 空间复杂度:图空间 O ( m ) O(m) O(m),标记数组空间 O ( n ) O(n) O(n)

题解二(BFS)

附赠一份 BFS 代码:

class Solution {
    fun countCompleteComponents(n: Int, edges: Array<IntArray>): Int {
        // 建图(邻接表)
        val graph = Array(n) { mutableListOf<Int>() }
        for (edge in edges) {
            graph[edge[0]].add(edge[1])
            graph[edge[1]].add(edge[0]) // 无向边
        }
        // 标记数组
        val visit = BooleanArray(n)
        // 枚举
        var ret = 0
        for (i in 0 until n) {
            if (visit[i]) continue
            var v = 0
            var e = 0
            // BFS
            var queue = LinkedList<Int>()
            queue.offer(i)
            visit[i] = true
            while (!queue.isEmpty()) {
                val temp = queue
                queue = LinkedList<Int>()
                for (j in temp) {
                    v += 1 // 增加节点
                    e += graph[j].size // 增加边(会统计两次)
                    for (to in graph[j]) {
                        if (!visit[to]) {
                            queue.offer(to)
                            visit[to] = true
                        }
                    }
                }
            }
            if (e == v * (v - 1)) ret++
        }
        return ret
    }
}

复杂度分析:

  • 时间复杂度: O ( n + m ) O(n + m) O(n+m) 其中 n 为节点数,m 为 edges 的长度;
  • 空间复杂度:图空间、标记数组空间和队列空间。

题解三(并查集)

附赠一份并查集代码:

class Solution {

    fun countCompleteComponents(n: Int, edges: Array<IntArray>): Int {
        val uf = UnionFind(n)
        for (edge in edges) {
            uf.union(edge[0], edge[1])
        }
        return uf.count()
    }

    private class UnionFind(n: Int) {
        private val parent = IntArray(n) { it }
        private val rank = IntArray(n)
        private val e = IntArray(n)
        private val v = IntArray(n) { 1 }

        fun find(x: Int): Int {
            // 路径压缩
            var a = x
            while (parent[a] != a) {
                parent[a] = parent[parent[a]]
                a = parent[a]
            }
            return a
        }

        fun union(x: Int, y: Int) {
            val rootX = find(x)
            val rootY = find(y)
            if (rootX == rootY) {
                e[rootX]++
            } else {
                // 按秩合并
                if (rank[rootX] < rank[rootY]) {
                    parent[rootX] = rootY
                    e[rootY] += e[rootX] + 1 // 增加边
                    v[rootY] += v[rootX] // 增加节点
                } else if (rank[rootY] > rank[rootX]) {
                    parent[rootY] = rootX
                    e[rootX] += e[rootY] + 1
                    v[rootX] += v[rootY]
                } else {
                    parent[rootY] = rootX
                    e[rootX] += e[rootY] + 1
                    v[rootX] += v[rootY]
                    rank[rootX]++
                }
            }
        }

        // 统计连通分量
        fun count(): Int {
            return parent.indices.count { parent[it] == it && v[it] * (v[it] - 1) / 2 == e[it] }
        }
    }
}

复杂度分析:

  • 时间复杂度: O ( n + a m ) O(n + am) O(n+am) 其中 n 为节点数,m 为 edges 的长度,其中 a a a 为反阿克曼函数。
  • 空间复杂度: O ( n ) O(n) O(n) 并查集空间。

往期回顾

  • LeetCode 单周赛第 344 场 · 手写递归函数的通用套路
  • LeetCode 单周赛第 343 场 · 结合「下一个排列」的贪心构造问题
  • LeetCode 双周赛第 104 场 · 流水的动态规划,铁打的结构化思考
  • LeetCode 双周赛第 103 场 · 区间求和的树状数组经典应用

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

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

相关文章

微信小程序入门02-安装mysql

我们上一篇介绍的是微信开发者工具的安装&#xff0c;开发一个小程序肯定要有后端服务&#xff0c;有后端服务首先要可以存储和查询数据。 数据库种类比较多&#xff0c;我们这里选择mysql&#xff0c;为啥选择这个呢&#xff0c;因为首先用的人多比较稳定&#xff0c;再一个免…

MapReduce:Index索引案例

案例需求 a.html hello world hello lucy hello jack hello liuyan b.html hello aaa aaa bbb bbb ccc hello liuyan liuyan tangyan c.html world hello liuyan tangyan tangyan aaa bbb ccc 计算每个单词在每个文件中出现的次数 aaa b.html-2 c.html-1 bbb b.h…

文本三剑客awk

awk 工作原理&#xff1a; 逐行读取文本&#xff0c;默认以空格或tab键为分隔符进行分隔&#xff0c;将分隔所得的各个字段保存到内建变量中&#xff0c;并按模式或者条件执行编辑命令。 sed命令常用于一整行的处理&#xff0c;而awk比较倾向于将一行分成多个“字段”然后再进…

Visual Studio Code 插件的开发、调试及发布完整详细教程

本篇文章主要讲解:Vscode的拓展插件,从环境安装到生成项目文件再到调试及部署发布的完整开发教程。 日期:2023年5月10日 vscode 1.78.1 一、准备node环境及安装yo 项目初始化,优先安装yo、再通过yo创建code及插件项目。 基础条件 需要先安装node,且node环境已经正确安装…

5.项目管理(测试)工具

目录 一、禅道 1.为什么需要禅道&#xff1f;&#xff08;仅从测试角度看&#xff09; 2.管理工具的对比 3.禅道的设计理念 4.软件开发的生命周期有哪些&#xff1f;&#xff08;软件开发的流程&#xff09; 二、selenium 1、什么是自动化测试&#xff1f; 2.UI自动化的…

2023年,最新linux c/c++后台开发学习路线分享

摘自零声教育课程大纲&#xff0c;8个技术维度项目实战&#xff0c;为你打通linux c/c后台开发的技术栈。 部分往期视频 c八股文重点&#xff0c;网络的posix api实现原理 8个方面讲解io_uring&#xff0c;重塑对异步io的理解 c后端开发中数据库异步连接、异步连接池的原理…

浅聊一下PTP

浅聊一下ptp 最近做了点时间同步相关工作&#xff0c;浅浅聊一下学习和了解的东西吧。 大概了解了一下PTP&#xff0c;NTP&#xff0c;PTPD&#xff0c;LinuxPTP 1.时钟同步 网络时钟同步包括频率同步和相位同步两个概念。 频率同步&#xff08;Frequency synchronization…

Hudi集成Spark与hudi表的创建

集成Hudi包 Spark-shell 方式启动 Spark SQL方式启动 SQL方式创建hudi建表 集成Hudi包 以下为hudi与spark版本的兼容 Hudi Supported Spark 3 version 0.12.x 3.3.x&#xff0c;3.2.x&#xff0c;3.1.x 0.11.x 3.2.x&#xff08;default build, Spark bundle only&…

浪漫行星,不浪漫你打我

先上效果图&#xff1a; 再上代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><style>import "https://fonts.googleapis.com/css2?familyMegrim&…

tftp文件传输协议报文解析

1&#xff0c;接着上一篇描述bootp,我们现在了解一下tftp协议。 先来看看tftp的五种报文格式 操作码补充说明&#xff1a; 读文件请求包&#xff1a;Read request&#xff0c;简写为RRQ&#xff0c;对应Opcode字段值为1 写文件请求包&#xff1a;Write requst&#xff0c;简…

练习SSM微博项目

微博项目 项目概述 ​ 该项目是一款社交媒体应用&#xff0c;用户可以在平台上发表短文、图片等信息&#xff0c;分享自己的想法、心情和生活。微博的用户群体广泛&#xff0c;包括个人、娱乐明星、公司、政府官方等。 项目功能 用户管理 用户可以注册微博账号&#xff0c;登…

​ES elasticsearch-analysis-dynamic-synonym​连接数据库动态更新synonym近义词

前言 在很多搜索场景中&#xff0c;我们希望能够搜索出搜索词相关的目标&#xff0c;同时也希望能搜索出其近义词相关的目标。例如在商品搜索中&#xff0c;搜索“瓠瓜”&#xff0c;也希望能够搜索出“西葫芦”&#xff0c;但“西葫芦”商品名称因不含有“瓠瓜”&#xff0c;导…

今年流行的人工智能AI 人脸生成器,你懂的。

使用人工智能 (AI) 继续革新我们与技术和环境互动的方式。AI 最令人兴奋的应用之一是人脸生成器&#xff0c;它可以根据输入数据创建逼真、高质量的图像。 在这篇博文中&#xff0c;我们将讨论当今可用的 10 大AI 人脸生成器&#xff0c;探索它们的功能和性能&#xff0c;并发…

DDD重构中台业务

大家好&#xff0c;我是易安&#xff01;今天我们谈一谈如何使用DDD重构中台业务。 DDD有两把利器&#xff0c;那就是它的战略设计和战术设计方法。中台在企业架构上更多偏向业务模型&#xff0c;形成中台的过程实际上也是业务领域不断细分的过程。在这个过程中我们会将同类通用…

selenium+Java环境搭建

目录 ①下载Chrome浏览器并查看浏览器版本 ②下载解压Chrome浏览器驱动 ③配置Java环境 ④将驱动文件放到jdk的bin文件目录下 ⑤验证环境是否搭建成功 1、创建java&#xff08;Maven&#xff09;项目&#xff0c;在pom.xml中添加依赖 2、在java文件创建Main类 &am…

[刷题]贪心入门

文章目录 贪心区间问题区间选点区间合并区间覆盖 哈夫曼树&#xff08;堆&#xff09;合并果子 排序不等式排队打水 绝对值不等式货仓选址 推出来的不等式耍杂技的牛 以前的题 贪心 贪心&#xff1a;每一步行动总是按某种指标选取最优的操作来进行&#xff0c; 该指标只看眼前&…

SpringBoot 整合ElasticSearch实现模糊查询,批量CRUD,排序,分页,高亮

准备工作 准备一个空的SpringBoot项目 写入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency>注意你的SpringBoot和你的es版本&#xff0…

都说测试行业饱和了,为啥我们公司给初级测试还能开到了12K?

故事起因&#xff1a; 最近我有个刚毕业的学生问我说&#xff1a;我感觉现在测试行业已经饱和了&#xff0c;也不是说饱和了&#xff0c;是初级的测试根本就没有公司要&#xff0c;哪怕你不要工资也没公司要你&#xff0c;测试刚学出来&#xff0c;没有任何的项目经验和工作经验…

2023年门店管理系统如何选?简单好用的门店管理系统有哪些?

开单收银效率低、商品管理混乱、记账对账耗时耗力还易出错...... 是我们在进行门店管理过程中常见的问题。 为了改善门店管理遇到的这几大问题&#xff0c;提高门店管理效率&#xff0c;越来越多的门店开始使用门店管理系统。 但如何选择简单实用、性价比高的门店管理系统&…

肠道核心菌属——Lachnoclostridium

谷禾健康 Lachnoclostridium属是一类革兰氏阳性菌&#xff0c;专性厌氧、形成孢子、属于Clostridiales目、Lachnospiraceae科、Firmicutes门。该属最初被描述为Clostridium phytofermentans&#xff0c;后来被重新分类为Lachnoclostridium属。 Lachnoclostridium属包括来自Lach…