简单
给你两个下标从 0 开始的整数数组 nums1
和 nums2
,它们分别含有 n
和 m
个元素。
请你计算以下两个数值:
0 <= i < n
中的下标 i
,满足 nums1[i]
在 nums2
中 至少 出现了一次。0 <= i < m
中的下标 i
,满足 nums2[i]
在 nums1
中 至少 出现了一次。请你返回一个长度为 2
的整数数组 answer
,按顺序 分别为以上两个数值。
示例 1:
输入:nums1 = [4,3,2,3,1], nums2 = [2,2,5,2,3,6]
输出:[3,4]
解释:分别计算两个数值:
- nums1 中下标为 1 ,2 和 3 的元素在 nums2 中至少出现了一次,所以第一个值为 3 。
- nums2 中下标为 0 ,1 ,3 和 4 的元素在 nums1 中至少出现了一次,所以第二个值为 4 。
示例 2:
输入:nums1 = [3,4,2,3], nums2 = [1,5]
输出:[0,0]
解释:两个数组中没有公共元素,所以两个值都为 0 。
提示:
n == nums1.length
m == nums2.length
1 <= n, m <= 100
1 <= nums1[i], nums2[i] <= 100
class Solution {
public int[] findIntersectionValues(int[] nums1, int[] nums2) {
Set<Integer> set1 = new HashSet<>();
for(int n : nums1) set1.add(n);
Set<Integer> set2 = new HashSet<>();
for(int n : nums2) set2.add(n);
int cnt1 = 0, cnt2 = 0;
for(int i = 0; i < nums1.length; i++){
if(set2.contains(nums1[i]))
cnt1++;
}
for(int i = 0; i < nums2.length; i++){
if(set1.contains(nums2[i]))
cnt2++;
}
return new int[]{cnt1, cnt2};
}
}
中等
给你一个下标从 0 开始的字符串 word
。
一次操作中,你可以选择 word
中任意一个下标 i
,将 word[i]
修改成任意一个小写英文字母。
请你返回消除 word
中所有相邻 近似相等 字符的 最少 操作次数。
两个字符 a
和 b
如果满足 a == b
或者 a
和 b
在字母表中是相邻的,那么我们称它们是 近似相等 字符。
示例 1:
输入:word = "aaaaa"
输出:2
解释:我们将 word 变为 "acaca" ,该字符串没有相邻近似相等字符。
消除 word 中所有相邻近似相等字符最少需要 2 次操作。
示例 2:
输入:word = "abddez"
输出:2
解释:我们将 word 变为 "ybdoez" ,该字符串没有相邻近似相等字符。
消除 word 中所有相邻近似相等字符最少需要 2 次操作。
示例 3:
输入:word = "zyxyxyz"
输出:3
解释:我们将 word 变为 "zaxaxaz" ,该字符串没有相邻近似相等字符。
消除 word 中所有相邻近似相等字符最少需要 3 次操作
提示:
1 <= word.length <= 100
word
只包含小写英文字母。class Solution {
/**
什么时候需要消除? 该字符和上一个字符相邻时一定要消除
*/
public int removeAlmostEqualCharacters(String word) {
int res = 0;
char pre = word.charAt(0);
for(int i = 1; i < word.length(); i++){
char c = word.charAt(i);
if(Math.abs(c - pre) <= 1){
res++;
pre = '0';
}else
pre = c;
}
return res;
}
}
中等
给你一个整数数组 nums
和一个整数 k
。
一个元素 x
在数组中的 频率 指的是它在数组中的出现次数。
如果一个数组中所有元素的频率都 小于等于 k
,那么我们称这个数组是 好 数组。
请你返回 nums
中 最长好 子数组的长度。
子数组 指的是一个数组中一段连续非空的元素序列。
示例 1:
输入:nums = [1,2,3,1,2,3,1,2], k = 2
输出:6
解释:最长好子数组是 [1,2,3,1,2,3] ,值 1 ,2 和 3 在子数组中的频率都没有超过 k = 2 。[2,3,1,2,3,1] 和 [3,1,2,3,1,2] 也是好子数组。
最长好子数组的长度为 6 。
示例 2:
输入:nums = [1,2,1,2,1,2,1,2], k = 1
输出:2
解释:最长好子数组是 [1,2] ,值 1 和 2 在子数组中的频率都没有超过 k = 1 。[2,1] 也是好子数组。
最长好子数组的长度为 2 。
示例 3:
输入:nums = [5,5,5,5,5,5,5], k = 4
输出:4
解释:最长好子数组是 [5,5,5,5] ,值 5 在子数组中的频率没有超过 k = 4 。
最长好子数组的长度为 4 。
提示:
1 <= nums.length <= 105
1 <= nums[i] <= 109
1 <= k <= nums.length
class Solution {
public int maxSubarrayLength(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>();
int left = 0, res = 0;
for(int right = 0; right < nums.length; right++){
map.merge(nums[right], 1, Integer::sum);
while(map.get(nums[right]) > k){
map.merge(nums[left], -1, Integer::sum);
left++;
}
res = Math.max(res, right - left + 1);
}
return res;
}
}
困难
一个公司在全国有 n
个分部,它们之间有的有道路连接。一开始,所有分部通过这些道路两两之间互相可以到达。
公司意识到在分部之间旅行花费了太多时间,所以它们决定关闭一些分部(也可能不关闭任何分部),同时保证剩下的分部之间两两互相可以到达且最远距离不超过 maxDistance
。
两个分部之间的 距离 是通过道路长度之和的 最小值 。
给你整数 n
,maxDistance
和下标从 0 开始的二维整数数组 roads
,其中 roads[i] = [ui, vi, wi]
表示一条从 ui
到 vi
长度为 wi
的 无向 道路。
请你返回关闭分部的可行方案数目,满足每个方案里剩余分部之间的最远距离不超过 maxDistance
。
注意,关闭一个分部后,与之相连的所有道路不可通行。
注意,两个分部之间可能会有多条道路。
示例 1:
输入:n = 3, maxDistance = 5, roads = [[0,1,2],[1,2,10],[0,2,10]]
输出:5
解释:可行的关闭分部方案有:
- 关闭分部集合 [2] ,剩余分部为 [0,1] ,它们之间的距离为 2 。
- 关闭分部集合 [0,1] ,剩余分部为 [2] 。
- 关闭分部集合 [1,2] ,剩余分部为 [0] 。
- 关闭分部集合 [0,2] ,剩余分部为 [1] 。
- 关闭分部集合 [0,1,2] ,关闭后没有剩余分部。
总共有 5 种可行的关闭方案。
示例 2:
输入:n = 3, maxDistance = 5, roads = [[0,1,20],[0,1,10],[1,2,2],[0,2,2]]
输出:7
解释:可行的关闭分部方案有:
- 关闭分部集合 [] ,剩余分部为 [0,1,2] ,它们之间的最远距离为 4 。
- 关闭分部集合 [0] ,剩余分部为 [1,2] ,它们之间的距离为 2 。
- 关闭分部集合 [1] ,剩余分部为 [0,2] ,它们之间的距离为 2 。
- 关闭分部集合 [0,1] ,剩余分部为 [2] 。
- 关闭分部集合 [1,2] ,剩余分部为 [0] 。
- 关闭分部集合 [0,2] ,剩余分部为 [1] 。
- 关闭分部集合 [0,1,2] ,关闭后没有剩余分部。
总共有 7 种可行的关闭方案。
示例 3:
输入:n = 1, maxDistance = 10, roads = []
输出:2
解释:可行的关闭分部方案有:
- 关闭分部集合 [] ,剩余分部为 [0] 。
- 关闭分部集合 [0] ,关闭后没有剩余分部。
总共有 2 种可行的关闭方案。
提示:
1 <= n <= 10
1 <= maxDistance <= 105
0 <= roads.length <= 1000
roads[i].length == 3
0 <= ui, vi <= n - 1
ui != vi
1 <= wi <= 1000
class Solution {
/**
0 <= roads.length <= 1000
枚举保留哪些节点,在这些节点之间连边
然后用Floyd算法求出任意两点之间的最短路,
若保留节点之间的最短路均不超过maxDistance,记录答案
*/
public int numberOfSets(int n, int maxDistance, int[][] roads) {
// 预处理原图的邻接矩阵g
int[][] g = new int[n][n];
for(int i = 0; i < n; i++){
Arrays.fill(g[i], Integer.MAX_VALUE / 2); // 加法防溢出
g[i][i] = 0;
}
for(int[] e : roads){
int x = e[0], y = e[1], wt = e[2];
g[x][y] = Math.min(g[x][y], wt);
g[y][x] = Math.min(g[y][x], wt);
}
int res = 0;
int[][] f = new int[n][n];
next:
//遍历所有方案数,当前方案i的二进制中为1的位置则表示该节点没有被删除,为0则表示被删除
for(int s = 0; s < (1 << n); s++){
for(int i = 0; i < n; i++){
if(((s >> i) & 1) == 1){
System.arraycopy(g[i], 0, f[i], 0, n);
}
}
// Floyd
for (int k = 0; k < n; k++) {
if ((s >> k & 1) == 0) continue;
for (int i = 0; i < n; i++) {
if ((s >> i & 1) == 0) continue;
for (int j = 0; j < n; j++) {
f[i][j] = Math.min(f[i][j], f[i][k] + f[k][j]);
}
}
}
for (int i = 0; i < n; i++) {
if ((s >> i & 1) == 0) continue;
for (int j = 0; j < n; j++) {
if ((s >> j & 1) == 1 && f[i][j] > maxDistance) {
continue next;
}
}
}
res++;
}
return res;
}
}
题单:
78. 子集
77. 组合
1286. 字母组合迭代器 1591
2397. 被列覆盖的最多行数 1719
2212. 射箭比赛中的最大得分 1869
77. 组合
1286. 字母组合迭代器 1591
2397. 被列覆盖的最多行数 1719
2212. 射箭比赛中的最大得分 1869
1601. 最多可达成的换楼请求数目 2119