文章目录
- [2924. 找到冠军 II](https://leetcode.cn/problems/find-champion-ii/description/?envType=daily-question&envId=2024-04-13!!!)
- 题目描述
- 思路分析
- [1702. 修改后的最大二进制字符串](https://leetcode.cn/problems/maximum-binary-string-after-change/)
- 题目描述
- 思路分析
- [830. 较大分组的位置](https://leetcode.cn/problems/positions-of-large-groups/)
- 题目描述
- 思路分析
2924. 找到冠军 II
题目描述
一场比赛中共有
n
支队伍,按从0
到n - 1
编号。每支队伍也是 有向无环图(DAG) 上的一个节点。给你一个整数
n
和一个下标从 0 开始、长度为m
的二维整数数组edges
表示这个有向无环图,其中edges[i] = [ui, vi]
表示图中存在一条从ui
队到vi
队的有向边。从
a
队到b
队的有向边意味着a
队比b
队 强 ,也就是b
队比a
队 弱 。在这场比赛中,如果不存在某支强于
a
队的队伍,则认为a
队将会是 冠军 。如果这场比赛存在 唯一 一个冠军,则返回将会成为冠军的队伍。否则,返回
-1
。
思路分析
思路1:
对于u->v
这条边,v肯定不是冠军
所以我们遍历所有的边,将那些v标记上,然后判断1到n的每一个节点,如果该节点为标记,则该节点可能为冠军。
注意:冠军只能有一个,如果有多个节点未被标记,说明找不到冠军,就返回-1。
class Solution {public int findChampion(int n, int[][] edges) {int ans = -1;boolean[] loser = new boolean[n]; // u->v, v一定不是冠军for (int[] e : edges) {loser[e[1]] = true;}for (int i = 0; i < n; ++i) {if (loser[i]) continue;if (ans == -1) {ans = i;} else { // 存在多个冠军return -1;}}return ans;}
}
思路2:
入度不为0的节点肯定不是冠军
所有我们先统计所有节点的入度,入度为0的节点可能是冠军
由于冠军只能有一个,所以如果有多个入度为0的节点,则返回-1.
class Solution {public int findChampion(int n, int[][] edges) {int[] in = new int[n];for (int[] e : edges) {in[e[1]]++;}int ans = -1;for (int i = 0; i < n; ++i) {if (in[i] > 0) continue;if (ans == -1) {ans = i;} else { return -1;}}return ans;}
}
1702. 修改后的最大二进制字符串
题目描述
给你一个二进制字符串
binary
,它仅有0
或者1
组成。你可以使用下面的操作任意次对它进行修改:
- 操作 1 :如果二进制串包含子字符串
"00"
,你可以用"10"
将其替换。
- 比方说, “00010” -> “10010”
- 操作 2 :如果二进制串包含子字符串
"10"
,你可以用"01"
将其替换。
- 比方说, “00010” -> “00001”
请你返回执行上述操作任意次以后能得到的 最大二进制字符串 。如果二进制字符串
x
对应的十进制数字大于二进制字符串y
对应的十进制数字,那么我们称二进制字符串x
大于二进制字符串y
。
思路分析
贪心
结论一:最终结果不存在两个相邻的0,因为00
通过操作1,可以变为10
,比00更大。
结论二:最终结果至多只有一个0。
假设存在多个0,并且多个0不相邻,例如字符串101011
,对于2 3 位置的10
,通过操作2,可以变为01
,所以整体字符串变为100111
,再通过操作1,00
变为10
,所以整体字符串变为110111
,这就是最终结果。
观察101011
到100111
,相当于将第二个0,移动到第一个0后面,1依次后移。
再观察100111
到110111
,除最后一个0外,其他位置的0变为1。
结论三:全为1的字符串直接返回
所以总结一下最终结果的构成:
假设第一个0出现的位置为i
,i位置后面1的个数为cnt
个,那么最终结果的后cnt
位肯定都是1,第i位置为0,第i位置其他的元素也全为1.
具体做法:统计第一个0后面1的个数,假设是one
个,字符串的长度为n
,那么最终结果= n - one - 1个1
+ 0
+ cnt个1
class Solution {public String maximumBinaryString(String binary) {int n = binary.length();int one = 0; // 记录第一个0后面的1的个数boolean flag = false; // 标记第一个0是否出现for (int i = 0; i < binary.length(); ++i) {if (flag && binary.charAt(i) == '1') {one++;}if (binary.charAt(i) == '0') {flag = true;}}if (!flag && one == 0) {// 如果全为1(0没有出现),直接返回binaryreturn binary;}StringBuilder sb = new StringBuilder();for (int i = 0; i < n - one - 1; ++i) {sb.append("1");}sb.append("0");for (int i = 0; i < one; ++i) {sb.append("1");}return sb.toString();}
}
830. 较大分组的位置
题目描述
在一个由小写字母构成的字符串
s
中,包含由一些连续的相同字符所构成的分组。例如,在字符串
s = "abbxxxxzyy"
中,就含有"a"
,"bb"
,"xxxx"
,"z"
和"yy"
这样的一些分组。分组可以用区间
[start, end]
表示,其中start
和end
分别表示该分组的起始和终止位置的下标。上例中的"xxxx"
分组用区间表示为[3,6]
。我们称所有包含大于或等于三个连续字符的分组为 较大分组 。
找到每一个 较大分组 的区间,按起始位置下标递增顺序排序后,返回结果。
思路分析
双指针
一个指针标记区间开始,一个指针标记区间结束
class Solution {public List<List<Integer>> largeGroupPositions(String s) {List<List<Integer>> ans = new ArrayList<>();List<Integer> t = new ArrayList<>();int l = 0, r = 1;while (l < s.length()) {if (r < s.length() && s.charAt(r) == s.charAt(r - 1)) {// 区间扩张r++;} else {if (r - l >= 3) {// 区间长度大于等于3,收集结果t.add(l);t.add(r - 1);ans.add(new ArrayList<>(t));t = new ArrayList<>();}l = r;r = l + 1;}}return ans;}
}