- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
本文已收录到 AndroidFamily ,技术和职场问题,请关注公众号 [彭旭锐] 提问.
大家好,我是小彭.
上周末是 LeetCode 第 339 场周赛,你参加了吗?这场周赛覆盖的知识点比较少,前三题很简单,第四题上难度.
2609. 最长平衡子字符串(Easy) 。
2610. 转换二维数组(Medium) 。
2611. 老鼠和奶酪(Medium) 。
2612. 最少翻转操作数(Hard) 。
https://leetcode.cn/problems/find-the-longest-balanced-substring-of-a-binary-string/ 。
给你一个仅由 0 和 1 组成的二进制字符串 s .
如果子字符串中 所有的 0 都在 1 之前 且其中 0 的数量等于 1 的数量,则认为 s 的这个子字符串是平衡子字符串。请注意,空子字符串也视作平衡子字符串.
返回 s 中最长的平衡子字符串长度.
子字符串是字符串中的一个连续字符序列.
简单模拟题.
维护连续 0 的计数 cnt0 和连续 1 的计数 cnt1 ,并在 cnt0 == cnt1 时更新最长平衡子串长度为 2 * cnt1 。另外,在每段 0 的起始位置重新计数.
class Solution {
fun findTheLongestBalancedSubstring(s: String): Int {
var index = 0
var cnt0 = 0
var cnt1 = 0
var ret = 0
while (index < s.length) {
if (s[index] == '0') {
// 每段 0 的起始位置清零
if (index > 0 && s[index - 1] == '1') {
cnt0 = 0
cnt1 = 0
}
cnt0++
} else {
cnt1++
}
if (cnt1 <= cnt0) ret = Math.max(ret, cnt1 * 2)
index++
}
return ret
}
}
复杂度分析:
https://leetcode.cn/problems/convert-an-array-into-a-2d-array-with-conditions/ 。
给你一个整数数组 nums 。请你创建一个满足以下条件的二维数组:
nums
中的元素。 返回结果数组。如果存在多种答案,则返回其中任何一种.
请注意,二维数组的每一行上可以存在不同数量的元素.
贪心思路:首先计算每个元素的出现次数,为了避免同一行的重复,将重复元素从上到下排列到不同行中.
优化:可以在一次遍历中完成,在出现更大出现次数时增加一行,在更新元素技术 cnt 后插入到第 cnt - 1 行.
class Solution {
fun findMatrix(nums: IntArray): List<List<Int>> {
val cnts = IntArray(201)
val ret = LinkedList<LinkedList<Int>>()
var maxCnt = 0
// 计数
for (num in nums) {
// 累加
val curCnt = ++cnts[num]
// 创建新行
if (curCnt > maxCnt) {
maxCnt = curCnt
ret.add(LinkedList<Int>())
}
// 分布
ret[curCnt - 1].add(num)
}
return ret
}
}
复杂度分析:
https://leetcode.cn/problems/mice-and-cheese/ 。
有两只老鼠和 n 块不同类型的奶酪,每块奶酪都只能被其中一只老鼠吃掉.
下标为 i 处的奶酪被吃掉的得分为:
reward1[i]
。 reward2[i]
。 给你一个正整数数组 reward1 ,一个正整数数组 reward2 ,和一个非负整数 k .
请你返回第一只老鼠恰好吃掉 k 块奶酪的情况下, 最大 得分为多少.
容易理解:为了使最终得分最大,应该让每只老鼠吃到尽可能大的奶酪.
由于两只老鼠吃的奶酪是互斥关系,因此我们可以先假设所有奶酪被第一只老鼠食得,然后再挑选 n - k 个奶酪还给第二只老鼠.
那么,对于每个位置 i ,将奶酪从第一只老鼠还给第二只老鼠存在差值 diff = reward2[i] - reward1[i] ,表示得分的差值为 diff 。差值为正得分变大,差值为负得分降低,显然降低越少越好.
因此,我们的算法是对 diff 排序,将得分降低越大的位置保留给第一只老鼠,其他还给第二只老鼠.
class Solution {
fun miceAndCheese(reward1: IntArray, reward2: IntArray, k: Int): Int {
// 贪心:优先选择差值最大的位置
val n = reward1.size
var ret = 0
val indexs = Array(n) { it }
// 升序
Arrays.sort(indexs) { i1, i2 ->
(reward2[i1] - reward1[i1]) - (reward2[i2] - reward1[i2])
}
for (i in 0 until n) {
ret += if (i < k) {
reward1[indexs[i]]
} else {
reward2[indexs[i]]
}
}
return ret
}
}
复杂度分析:
https://leetcode.cn/problems/minimum-reverse-operations/ 。
给你一个整数 n 和一个在范围 [0, n - 1] 以内的整数 p ,它们表示一个长度为 n 且下标从 0 开始的数组 arr ,数组中除了下标为 p 处是 1 以外,其他所有数都是 0 .
同时给你一个整数数组 banned ,它包含数组中的一些位置。 banned 中第 i 个位置表示 arr[banned[i]] = 0 ,题目保证 banned[i] != p .
你可以对 arr 进行 若干次 操作。一次操作中,你选择大小为 k 的一个 子数组 ,并将它 翻转 。在任何一次翻转操作后,你都需要确保 arr 中唯一的 1 不会到达任何 banned 中的位置。换句话说, arr[banned[i]] 始终 保持 0 .
请你返回一个数组 ans ,对于 ** [0, n - 1] 之间的任意下标 i , ans[i] 是将 1 放到位置 i 处的 最少 翻转操作次数,如果无法放到位置 i 处,此数为 -1 .
i
, ans[i]
相互之间独立计算。
分析 1:对于翻转窗口 [L, R] 中的位置 i,翻转后的下标为 $\frac{L+R}{2} + (\frac{L+R}{2} - i) = L + R - i$ 。
分析 2:首先位置 p 的翻转次数恒等于 0,而 banned 数组表示的位置翻转次数恒等于 -1.
分析 3:当位置 i 位于翻转窗口的左半部分时,将翻转到更大位置;当位置 i 位于翻转窗口的右半部分时,将翻转到更小位置; 。
分析 4:现在我们需要分析位置 i (初始 i 为 0 )可以翻转到的位置:
i
作为翻转窗口的左右边界,则有:
i + k - 1
; i - k + 1
。 2
的等差数列。 因此,i 可以翻转的区间为 [i - k + 1, i + k - 1] 中间隔 2 的位置(排除 banned 数组),或者理解为奇偶性相同的下标.
分析 5:由于翻转窗口有位置限制,会限制翻转:
0
时,且 i
位于翻转窗口的右半部分时(准备向左翻),则翻转后的位置是 0 + (k - 1) - i = k - 1 - i
。由于窗口无法继续左移,所以小于 k - i - 1
的位置都不可达; n - 1
时,且 i
位于翻转窗口的左边部分时(准备向右翻),则翻转后的位置是 (n - k) + (n - 1) - i = 2n - k - i - 1
。由于窗口无法继续右移,所以大于 2n - k - i - 1
的位置都不可达。 综上,可得翻转后区间为 [max(i - k + 1, k - i - 1), min(i + k - 1, 2n - k - i - 1)] 中与 i 奇偶性相同的位置.
至此,容易发现问题可以用拓扑排序(BFS 写法)解决:初始时将 p 位置入队,随后每一轮的翻转次数 + 1,并将该位置入队.
class Solution {
fun minReverseOperations(n: Int, p: Int, banned: IntArray, k: Int): IntArray {
val ret = IntArray(n) { -1 }
// 初始位
ret[p] = 0
// 禁止位
val bannedSet = banned.toHashSet()
// BFS(最小跳转索引)
val queue = LinkedList<Int>()
queue.offer(p)
while (!queue.isEmpty()) {
val i = queue.poll()!!
val min = Math.max(i - k + 1, k - i - 1)
val max = Math.min(i + k - 1, 2 * n - k - i - 1)
val curStep = ret[i] + 1
for (j in min..max step 2) {
// 不可达
if (bannedSet.contains(j)) continue
// 已访问
if (ret[j] != -1) continue
// 可达
ret[j] = curStep
// 入队
queue.offer(j)
}
}
return ret
}
}
复杂度分析:
在题解一中,当 k 比较大时每轮 BFS 中会重复判断已经被标记过的位置,如何避免呢?我们可以提前将所有下标加入到散列表中,在每次标记后将下标从散列表移除,这样能避免重复访问已经标记过的位置.
其次,由于每轮中需要标记的区间位于 [min, max] ,那么我们可以将散列表升级为基于平衡二叉树的 TreeSet,以便在 O(lgn) 时间内找到区间中的元素。具体方式是寻找树中大于等于 min 的最小元素(且小于等于 max ),将其标记和移除.
最后,由于偶数下标和奇数下标是分开的,所以需要建立两个平衡二叉树.
class Solution {
fun minReverseOperations(n: Int, p: Int, banned: IntArray, k: Int): IntArray {
val ret = IntArray(n) { -1 }
// 初始位
ret[p] = 0
// 禁止位
val bannedSet = banned.toHashSet()
// 平衡二叉树
val sets = Array(2) { TreeSet<Int>() }
for (i in 0 until n) {
if (i != p && !bannedSet.contains(i)) sets[i % 2].add(i)
}
// BFS(最小跳转索引)
val queue = LinkedList<Int>()
queue.offer(p)
while (!queue.isEmpty()) {
val i = queue.poll()!!
val min = Math.max(i - k + 1, k - i - 1)
val max = Math.min(i + k - 1, 2 * n - k - i - 1)
val curStep = ret[i] + 1
// 根据左端点确定奇偶性(右端点也行)
val set = sets[min % 2]
// 枚举平衡树中的 [min,max] 区间
while (true) {
val index = set.ceiling(min) ?: break // 大于等于 min 的最小键值
if (index > max) break
// 标记并删除
set.remove(index)
ret[index] = curStep
// 入队
queue.offer(index)
}
}
return ret
}
}
复杂度分析:
点击上方按钮关注 每周持续原创更新 与你一起深度思考 。
The End 。
—— 我 们 下 次 见 —— 。
最后此篇关于刷爆LeetCode周赛339,贪心/排序/拓扑排序/平衡二叉树的文章就讲到这里了,如果你想了解更多关于刷爆LeetCode周赛339,贪心/排序/拓扑排序/平衡二叉树的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在尝试对每个条目有多个值的关联数组进行排序。 例如 [0] => stdClass Object ( [type] => node [sid] => 158 [score] => 0.059600
我在 mysql 中有“日期”列以这种格式保存日期 2014 年 9 月 17 日(日-月-年) 我需要对它们进行升序排序,所以我使用了这个命令: SELECT * FROM table ORDER
我目前正在将 MySQL 存储过程重写为 MS SQL 存储过程,但遇到了问题。 在 MySQL 存储过程中,有一个游标,它根据最近的日期 (effdate) 选择一个值并将其放入变量 (thestt
我想要 gwt r.QuestionId- 排序。但是我得到未排序的 QuestionId 尽管我提到了 QuestionId ASC 的顺序。 SELECT r.QuestionId,
我有一个关于在 scandir 函数中排序的基本问题。到目前为止,我阅读了 POSIX readdir 的手册页,但没有找到有关订购保证的具体信息。 但是当我遍历大目录(无法更改,只读)时,我在多个系
基本上我必须从 SQL 数据库中构建项目列表,但是用户可以选择对 7 个过滤器的任意组合进行过滤,也可以选择要排序的列以及按方向排序。 正如您可以想象的那样,这会以大量不同的组合进行编码,并且数据集非
我有两张 table 。想象第一个是一个目录,包含很多文件(第二个表)。 第二个表(文件)包含修改日期。 现在,我想选择所有目录并按修改日期 ASC 对它们进行排序(因此,最新的修改最上面)。我不想显
我想先根据用户的状态然后根据用户名来排序我的 sql 请求。该状态由 user_type 列设置: 1=活跃,2=不活跃,3=创始人。 我会使用此请求来执行此操作,但它不起作用,因为我想在“活跃”成员
在 C++ 中,我必须实现一个“类似 Excel/Access”(引用)的查询生成器,以允许对数据集进行自定义排序。如果您在 Excel 中使用查询构建器或 SQL 中的“ORDER BY a, b,
我面临这样的挑战: 检索按字段 A 排序的文档 如果字段 B 存在/不为空 . 否则 按字段排序 C. 在 SQL 世界中,我会做两个查询并创建一个 UNION SELECT,但我不知道如何从 Mon
我想对源列表执行以下操作: map 列表 排序 折叠 排序 展开 列表 其中一些方法(例如map和toList)是可链接的,因为它们返回非空对象。但是,sort 方法返回 void,因为它对 List
我制作了一个用于分析 Windows 日志消息编号的脚本。 uniq -c 数字的输出很难预测,因为根据数字的大小会有不同的空白。此时,我手动删除了空白。 这是对消息进行排序和计数的命令: cat n
我有以下词典: mydict1 = {1: 11, 2: 4, 5: 1, 6: 1} mydict2 = {1: 1, 5: 1} 对于它们中的每一个,我想首先按值(降序)排序,然后按键(升序)排序
我刚刚开始使用泛型,目前在对多个字段进行排序时遇到问题。 案例: 我有一个 PeopleList 作为 TObjectList我希望能够通过一次选择一个排序字段,但尽可能保留以前的排序来制作类似 Ex
有没有办法在 sql 中组合 ORDER BY 和 IS NULL 以便我可以在列不为空时按列排序,但如果它为null,按另一列排序? 最佳答案 类似于: ORDER BY CASE WHEN
我有一个包含 2 列“id”和“name”的表。 id 是常规的自动增量索引,name 只是 varchar。 id name 1 john 2 mary 3 pop 4 mary 5 j
场景 网站页面有一个带有分页、过滤、排序功能的表格 View 。 表中的数据是从REST API服务器获取的,数据包含数百万条记录。 数据库 REST API 服务器 Web 服务器 浏览器 问
假设我有一本字典,其中的键(单词)和值(分数)如下: GOD 8 DONG 16 DOG 8 XI 21 我想创建一个字典键(单词)的 NSArray,首先按分数排序,然后按字
如何在 sphinx 上通过 sql 命令选择前 20 行按标题 WEIGHT 排序,接下来 20 行按标题 ASC 排序(总共 40 个结果),但不要给出重复的标题输出。 我尝试了这个 sql 命令
我有一个奇怪的问题,当从 SQLite 数据库中选择信息并根据日期排序时,返回的结果无效。 我的SQL语句是这样的: Select pk from usersDates order by dateti
我是一名优秀的程序员,十分优秀!