第一次参加周赛,费死劲A了两道。以后希望可以坚持参加周赛。
5971.打折购买糖果的最小开销
问题:一家商店正在打折销售糖果。每购买 两个 糖果,商店会 免费 送一个糖果。
免费送的糖果唯一的限制是:它的价格需要小于等于购买的两个糖果价格的 较小值 。
- 比方说,总共有
4
个糖果,价格分别为1
,2
,3
和4
,一位顾客买了价格为2
和3
的糖果,那么他可以免费获得价格为1
的糖果,但不能获得价格为4
的糖果。
给你一个下标从 0 开始的整数数组 cost
,其中 cost[i]
表示第 i
个糖果的价格,请你返回获得 所有 糖果的 最小 总开销。
示例:
输入:cost = [1,2,3]
输出:5
解释:我们购买价格为 2 和 3 的糖果,然后免费获得价格为 1 的糖果。
总开销为 2 + 3 = 5 。这是开销最小的 唯一 方案。
注意,我们不能购买价格为 1 和 3 的糖果,并免费获得价格为 2 的糖果。
这是因为免费糖果的价格必须小于等于购买的 2 个糖果价格的较小值。
输入:cost = [6,5,7,9,2,2]
输出:23
解释:最小总开销购买糖果方案为:
- 购买价格为 9 和 7 的糖果
- 免费获得价格为 6 的糖果
- 购买价格为 5 和 2 的糖果
- 免费获得价格为 2 的最后一个糖果
因此,最小总开销为 9 + 7 + 5 + 2 = 23 。
输入:cost = [5,5]
输出:10
解释:由于只有 2 个糖果,我们需要将它们都购买,而且没有免费糖果。
所以总最小开销为 5 + 5 = 10 。
思路:先排序,然后从后往前遍历,三个三个一组,第三个免费,若不足三个,则这组没有可以免费得到的。
class Solution {
public int minimumCost(int[] cost) {
Arrays.sort(cost);
int minCost = 0, count = 1;
for(int i = cost.length - 1; i >= 0; i--){
if(count % 3 != 0){
minCost += cost[i];
}
count++;
}
return minCost;
}
}
5972.统计隐藏数组数目
问题:给你一个下标从 0 开始且长度为 n
的整数数组 differences
,它表示一个长度为 n + 1
的 隐藏 数组 相邻 元素之间的 差值 。更正式的表述为:我们将隐藏数组记作 hidden
,那么 differences[i] = hidden[i + 1] - hidden[i]
。
同时给你两个整数 lower
和 upper
,它们表示隐藏数组中所有数字的值都在 闭 区间 [lower, upper]
之间。
- 比方说,
differences = [1, -3, 4]
,lower = 1
,upper = 6
,那么隐藏数组是一个长度为4
且所有值都在1
和6
(包含两者)之间的数组。[3, 4, 1, 5]
和[4, 5, 2, 6]
都是符合要求的隐藏数组。[5, 6, 3, 7]
不符合要求,因为它包含大于6
的元素。[1, 2, 3, 4]
不符合要求,因为相邻元素的差值不符合给定数据。
请你返回 符合 要求的隐藏数组的数目。如果没有符合要求的隐藏数组,请返回 0
。
示例:
输入:differences = [1,-3,4], lower = 1, upper = 6
输出:2
解释:符合要求的隐藏数组为:
- [3, 4, 1, 5]
- [4, 5, 2, 6]
所以返回 2 。
输入:differences = [3,-4,5,1,-2], lower = -4, upper = 5
输出:4
解释:符合要求的隐藏数组为:
- [-3, 0, -4, 1, 2, 0]
- [-2, 1, -3, 2, 3, 1]
- [-1, 2, -2, 3, 4, 2]
- [0, 3, -1, 4, 5, 3]
所以返回 4 。
输入:differences = [4,-7,2], lower = 3, upper = 6
输出:0
解释:没有符合要求的隐藏数组,所以返回 0 。
思路:
- 首先是暴力解,隐藏数组的本质就是,从[lower, upper]区间的某个数开始,依次加上
differences
数组的值,若计算过程中,每个元素的值都在[lower, upper]区间内,则算是一种合法的隐藏数组情况。但是超时了。
class Solution {
private int res;
public int numberOfArrays(int[] differences, int lower, int upper) {
res = 0;
for(int i = lower; i <= upper; i++){
helper(differences, i, lower, upper, 0);
}
return res;
}
private void helper(int[] choice, int num, int lower, int upper, int index){
if(num < lower || num > upper){
return;
}
if(index == choice.length){
res++;
return;
}
helper(choice, num + choice[index],lower, upper, index + 1);
}
}
- 我们并不需要求这个隐藏数组的具体值,只需要判断以某个数开头的隐藏数组是否存在。怎么判断呢?计算出
differences
数组的前缀和,然后找到前缀和中的最大值max
和最小值min
,对于前元素i
来说,若(i + min) >= lower && (i + max) <= upper
,则以i
开头的隐藏数组是存在的。否则不存在。 - 为什么这样可以计算出来呢,前面说了,隐藏数组中的元素是这样来的:从
[lower, upper]
区间的某个数开始,依次加上differences
数组的值。也就是说对于i来说,i依次加上前缀和中对应的值就可以得到隐藏数组的各个元素。前面说了,我们并不需要求这个隐藏数组的具体值,只需要判断以某个数开头的隐藏数组是否存在。若i+前缀和中的最小值都大于等于lower
,则以i开始的隐藏数组的每个元素都大于等于lower,同理,若i+前缀和中的最大值都小于等于upper
,则以i开始的隐藏数组的每个元素都小于等于upper。同时满足这两个条件,说明以i开始的隐藏数组是存在的。
class Solution {
public int numberOfArrays(int[] differences, int lower, int upper) {
int res = 0;
int sum = 0, min = Integer.MAX_VALUE, max = Integer.MIN_VALUE;
for(int j = 0; j < differences.length; j++){
sum += differences[j];
min = Math.min(min, sum);
max = Math.max(max, sum);
}
for(int i = lower; i <= upper; i++){
if((i + min) >= lower && (i + max) <= upper){
res++;
}
}
return res;
}
}
整理思路,记录博客,以便复习。若有误,望指正~