文章目录
- 双周赛122
- [3010. 将数组分成最小总代价的子数组 I](https://leetcode.cn/problems/divide-an-array-into-subarrays-with-minimum-cost-i/)
- [3011. 判断一个数组是否可以变为有序](https://leetcode.cn/problems/find-if-array-can-be-sorted/)
- [3012. 通过操作使数组长度最小](https://leetcode.cn/problems/minimize-length-of-array-using-operations/)
- [3013. 将数组分成最小总代价的子数组 II](https://leetcode.cn/problems/divide-an-array-into-subarrays-with-minimum-cost-ii/)
双周赛122
3010. 将数组分成最小总代价的子数组 I
简单
给你一个长度为 n
的整数数组 nums
。
一个数组的 代价 是它的 第一个 元素。比方说,[1,2,3]
的代价是 1
,[3,4,1]
的代价是 3
。
你需要将 nums
分成 3
个 连续且没有交集 的子数组。
请你返回这些子数组的 最小 代价 总和 。
示例 1:
输入:nums = [1,2,3,12]
输出:6
解释:最佳分割成 3 个子数组的方案是:[1] ,[2] 和 [3,12] ,总代价为 1 + 2 + 3 = 6 。
其他得到 3 个子数组的方案是:
- [1] ,[2,3] 和 [12] ,总代价是 1 + 2 + 12 = 15 。
- [1,2] ,[3] 和 [12] ,总代价是 1 + 3 + 12 = 16 。
示例 2:
输入:nums = [5,4,3]
输出:12
解释:最佳分割成 3 个子数组的方案是:[5] ,[4] 和 [3] ,总代价为 5 + 4 + 3 = 12 。
12 是所有分割方案里的最小总代价。
示例 3:
输入:nums = [10,3,1,1]
输出:12
解释:最佳分割成 3 个子数组的方案是:[10,3] ,[1] 和 [1] ,总代价为 10 + 1 + 1 = 12 。
12 是所有分割方案里的最小总代价。
提示:
3 <= n <= 50
1 <= nums[i] <= 50
模拟
class Solution {
public int minimumCost(int[] nums) {
int n = nums.length;
int res = Integer.MAX_VALUE;
for(int j = 1; j < n; j++){
for(int k = j+1; k < n; k++)
res = Math.min(res, nums[0] + nums[j] + nums[k]);
}
return res;
}
}
3011. 判断一个数组是否可以变为有序
中等
给你一个下标从 0 开始且全是 正 整数的数组 nums
。
一次 操作 中,如果两个 相邻 元素在二进制下数位为 1 的数目 相同 ,那么你可以将这两个元素交换。你可以执行这个操作 任意次 (也可以 0 次)。
如果你可以使数组变有序,请你返回 true
,否则返回 false
。
示例 1:
输入:nums = [8,4,2,30,15]
输出:true
解释:我们先观察每个元素的二进制表示。 2 ,4 和 8 分别都只有一个数位为 1 ,分别为 "10" ,"100" 和 "1000" 。15 和 30 分别有 4 个数位为 1 :"1111" 和 "11110" 。
我们可以通过 4 个操作使数组有序:
- 交换 nums[0] 和 nums[1] 。8 和 4 分别只有 1 个数位为 1 。数组变为 [4,8,2,30,15] 。
- 交换 nums[1] 和 nums[2] 。8 和 2 分别只有 1 个数位为 1 。数组变为 [4,2,8,30,15] 。
- 交换 nums[0] 和 nums[1] 。4 和 2 分别只有 1 个数位为 1 。数组变为 [2,4,8,30,15] 。
- 交换 nums[3] 和 nums[4] 。30 和 15 分别有 4 个数位为 1 ,数组变为 [2,4,8,15,30] 。
数组变成有序的,所以我们返回 true 。
注意我们还可以通过其他的操作序列使数组变得有序。
示例 2:
输入:nums = [1,2,3,4,5]
输出:true
解释:数组已经是有序的,所以我们返回 true 。
示例 3:
输入:nums = [3,16,8,4,2]
输出:false
解释:无法通过操作使数组变为有序。
提示:
1 <= nums.length <= 100
1 <= nums[i] <= 28
方法一:冒泡排序
class Solution {
public boolean canSortArray(int[] nums) {
int n = nums.length;
for(int j = n-1; j > 0; j--){
for(int i = 0; i < j; i++){
if(nums[i] < nums[i+1])
continue;
if(Integer.bitCount(nums[i]) == Integer.bitCount(nums[i+1]))
swap(nums, i, i+1);
}
}
for(int i = 0; i < n-1; i++){
if(nums[i] > nums[i+1])
return false;
}
return true;
}
public void swap(int[] nums, int a, int b){
int tmp = nums[a];
nums[a] = nums[b];
nums[b] = tmp;
}
}
方法二:分组循环
class Solution {
/**
如果每一段的最小值,都大于等于上一段的最大值,那么我们就能把数组排成有序的。
*/
public boolean canSortArray(int[] nums) {
int n = nums.length;
int i = 0, preMax = 0;
while(i < n){
int mn = nums[i], mx = mn;
int ones = Integer.bitCount(mn);
for(i++; i < n && Integer.bitCount(nums[i]) == ones; i++){
mn = Math.min(mn, nums[i]);
mx = Math.max(mx, nums[i]);
}
// 这一段的最小值 < 上一段最大值,此时构不成有序
if(mn < preMax){
return false;
}
preMax = mx;
}
return true;
}
}
3012. 通过操作使数组长度最小
中等
给你一个下标从 0 开始的整数数组 nums
,它只包含 正 整数。
你的任务是通过进行以下操作 任意次 (可以是 0 次) 最小化 nums
的长度:
- 在
nums
中选择 两个不同 的下标i
和j
,满足nums[i] > 0
且nums[j] > 0
。 - 将结果
nums[i] % nums[j]
插入nums
的结尾。 - 将
nums
中下标为i
和j
的元素删除。
请你返回一个整数,它表示进行任意次操作以后 nums
的 最小长度 。
示例 1:
输入:nums = [1,4,3,1]
输出:1
解释:使数组长度最小的一种方法是:
操作 1 :选择下标 2 和 1 ,插入 nums[2] % nums[1] 到数组末尾,得到 [1,4,3,1,3] ,然后删除下标为 2 和 1 的元素。
nums 变为 [1,1,3] 。
操作 2 :选择下标 1 和 2 ,插入 nums[1] % nums[2] 到数组末尾,得到 [1,1,3,1] ,然后删除下标为 1 和 2 的元素。
nums 变为 [1,1] 。
操作 3 :选择下标 1 和 0 ,插入 nums[1] % nums[0] 到数组末尾,得到 [1,1,0] ,然后删除下标为 1 和 0 的元素。
nums 变为 [0] 。
nums 的长度无法进一步减小,所以答案为 1 。
1 是可以得到的最小长度。
示例 2:
输入:nums = [5,5,5,10,5]
输出:2
解释:使数组长度最小的一种方法是:
操作 1 :选择下标 0 和 3 ,插入 nums[0] % nums[3] 到数组末尾,得到 [5,5,5,10,5,5] ,然后删除下标为 0 和 3 的元素。
nums 变为 [5,5,5,5] 。
操作 2 :选择下标 2 和 3 ,插入 nums[2] % nums[3] 到数组末尾,得到 [5,5,5,5,0] ,然后删除下标为 2 和 3 的元素。
nums 变为 [5,5,0] 。
操作 3 :选择下标 0 和 1 ,插入 nums[0] % nums[1] 到数组末尾,得到 [5,5,0,0] ,然后删除下标为 0 和 1 的元素。
nums 变为 [0,0] 。
nums 的长度无法进一步减小,所以答案为 2 。
2 是可以得到的最小长度。
示例 3:
输入:nums = [2,3,4]
输出:1
解释:使数组长度最小的一种方法是:
操作 1 :选择下标 1 和 2 ,插入 nums[1] % nums[2] 到数组末尾,得到 [2,3,4,3] ,然后删除下标为 1 和 2 的元素。
nums 变为 [2,3] 。
操作 2 :选择下标 1 和 0 ,插入 nums[1] % nums[0] 到数组末尾,得到 [2,3,1] ,然后删除下标为 1 和 0 的元素。
nums 变为 [1] 。
nums 的长度无法进一步减小,所以答案为 1 。
1 是可以得到的最小长度。
提示:
1 <= nums.length <= 105
1 <= nums[i] <= 109
脑经急转弯
https://leetcode.cn/problems/minimize-length-of-array-using-operations/solutions/2613059/on-nao-jin-ji-zhuan-wan-pythonjavacgo-by-2lea/
class Solution {
/**
1. 设 x = min(nums), x % 其它数字y = x, 该操作等价于,移除y (y > x)
2. 如果数组中的最小值只有一个,我们可以操作只剩下一个属
3. 如果最小值不止一个,如果能构造出一个小于m = min(nums)的正整数,也可以返回1
结论:当且仅当nums中有不是m的倍数的数,我们才能构造出一个小于m的正整数
只要数组里面的元素不都是最小元素的倍数,就能使长度变成一
如果所有数都是m的倍数,可以用m先把大于m的数都移除,然后剩下cnt个m两两一对消除
*/
public int minimumArrayLength(int[] nums) {
int m = Integer.MAX_VALUE;
for (int x : nums) {
m = Math.min(m, x);
}
for (int x : nums) {
if (x % m > 0) {
return 1;
}
}
int cnt = 0;
for (int x : nums) {
if (x == m) {
cnt++;
}
}
return (cnt + 1) / 2;
}
}
3013. 将数组分成最小总代价的子数组 II
困难
给你一个下标从 0 开始长度为 n
的整数数组 nums
和两个 正 整数 k
和 dist
。
一个数组的 代价 是数组中的 第一个 元素。比方说,[1,2,3]
的代价为 1
,[3,4,1]
的代价为 3
。
你需要将 nums
分割成 k
个 连续且互不相交 的子数组,满足 第二 个子数组与第 k
个子数组中第一个元素的下标距离 不超过 dist
。换句话说,如果你将 nums
分割成子数组 nums[0..(i1 - 1)], nums[i1..(i2 - 1)], ..., nums[ik-1..(n - 1)]
,那么它需要满足 ik-1 - i1 <= dist
。
请你返回这些子数组的 最小 总代价。
示例 1:
输入:nums = [1,3,2,6,4,2], k = 3, dist = 3
输出:5
解释:将数组分割成 3 个子数组的最优方案是:[1,3] ,[2,6,4] 和 [2] 。这是一个合法分割,因为 ik-1 - i1 等于 5 - 2 = 3 ,等于 dist 。总代价为 nums[0] + nums[2] + nums[5] ,也就是 1 + 2 + 2 = 5 。
5 是分割成 3 个子数组的最小总代价。
示例 2:
输入:nums = [10,1,2,2,2,1], k = 4, dist = 3
输出:15
解释:将数组分割成 4 个子数组的最优方案是:[10] ,[1] ,[2] 和 [2,2,1] 。这是一个合法分割,因为 ik-1 - i1 等于 3 - 1 = 2 ,小于 dist 。总代价为 nums[0] + nums[1] + nums[2] + nums[3] ,也就是 10 + 1 + 2 + 2 = 15 。
分割 [10] ,[1] ,[2,2,2] 和 [1] 不是一个合法分割,因为 ik-1 和 i1 的差为 5 - 1 = 4 ,大于 dist 。
15 是分割成 4 个子数组的最小总代价。
示例 3:
输入:nums = [10,8,18,9], k = 3, dist = 1
输出:36
解释:将数组分割成 4 个子数组的最优方案是:[10] ,[8] 和 [18,9] 。这是一个合法分割,因为 ik-1 - i1 等于 2 - 1 = 1 ,等于 dist 。总代价为 nums[0] + nums[1] + nums[2] ,也就是 10 + 8 + 18 = 36 。
分割 [10] ,[8,18] 和 [9] 不是一个合法分割,因为 ik-1 和 i1 的差为 3 - 1 = 2 ,大于 dist 。
36 是分割成 3 个子数组的最小总代价。
提示:
3 <= n <= 105
1 <= nums[i] <= 109
3 <= k <= n
k - 2 <= dist <= n - 2
https://leetcode.cn/problems/divide-an-array-into-subarrays-with-minimum-cost-ii/solutions/2614067/liang-ge-you-xu-ji-he-wei-hu-qian-k-1-xi-zdzx/