文章目录
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没有出现),直接返回binary
return 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;
}
}