2021-02-28 第 230 场周赛
1773. 统计匹配检索规则的物品数量
思路:签到题
class Solution {
public int keyToIndex(String ruleKey) {
if("type".equals(ruleKey)) {
return 0;
} else if("color".equals(ruleKey)) {
return 1;
} else {
return 2;
}
}
public int countMatches(List<List<String>> items, String ruleKey, String ruleValue) {
int res = 0;
int index = keyToIndex(ruleKey);
for(List<String> item : items) {
String value = item.get(index);
if(value.equals(ruleValue)) {
res++;
}
}
return res;
}
}
1774. 最接近目标价格的甜点成本
思路:这道题的数据量比较小,一看就可以暴力来做。遍历每种基料,然后使用三进制状态压缩来枚举每种配料的使用。
class Solution {
// 数字转化为三进制
public String getTernaryNum(int num) {
StringBuffer sb = new StringBuffer();
while(num > 0) {
sb.append(num % 3);
num /= 3;
}
return sb.toString();
}
public int closestCost(int[] baseCosts, int[] toppingCosts, int target) {
int res = Integer.MAX_VALUE, mx = Integer.MAX_VALUE;
int m = toppingCosts.length;
for(int baseCost : baseCosts) {
for(int i = 0;i < Math.pow(3,m);i++) {
int toppingCost = 0;
String ternaryNumber = getTernaryNum(i);
// System.out.println("" + i + " " + ternaryNumber);
for(int j = 0;j < ternaryNumber.length();j++) {
char cnt = ternaryNumber.charAt(j);
if(cnt != '0') {
toppingCost += ((cnt - '0') * toppingCosts[j]);
}
}
int tot = baseCost + toppingCost;
if(Math.abs(tot - target) < mx || (Math.abs(tot - target) == mx && tot < res)) {
res = tot;
mx = Math.abs(tot - target);
}
}
}
return res;
}
}
1775. 通过最少操作次数使数组的和相等
思路:参考零神的题解,思路真的太妙了
class Solution {
public int minOperations(int[] nums1, int[] nums2) {
int sum1 = 0, sum2 = 0, res = 0;
for(int num : nums1) sum1 += num;
for(int num : nums2) sum2 += num;
if(sum1 > sum2) return minOperations(nums2, nums1);
int[] cnt = new int[6];
for(int num : nums1) {
cnt[6-num]++;
}
for(int num : nums2) {
cnt[num-1]++;
}
int diff = sum2 - sum1;
for(int i = 5;i > 0 && diff > 0;i--) {
while(diff > 0 && cnt[i] > 0) {
diff -= i;
cnt[i]--;
res++;
}
}
return diff > 0 ? -1 : res;
}
}
里面的计算可以加速
class Solution {
public int minOperations(int[] nums1, int[] nums2) {
int sum1 = 0, sum2 = 0, res = 0;
for(int num : nums1) sum1 += num;
for(int num : nums2) sum2 += num;
if(sum1 > sum2) return minOperations(nums2, nums1);
int[] cnt = new int[6];
for(int num : nums1) {
cnt[6-num]++;
}
for(int num : nums2) {
cnt[num-1]++;
}
int diff = sum2 - sum1;
for(int i = 5;i > 0 && diff > 0;i--) {
if(diff >= cnt[i] * i) {
diff -= (cnt[i] * i);
res += cnt[i];
cnt[i] = 0;
} else {
int tmp = diff / i;
res += tmp;
if(diff % i != 0) res++;
diff = 0;
}
}
return diff > 0 ? -1 : res;
}
}
1776. 车队 II
思路:参考oldyan大佬的题解,比较重要的思路是:如果answer[i]
为正数,那么一定是cars[i]
和某个cars[j]
发生了碰撞,其中j>i
且speed[j]<speed[i]
。相撞之后,会形成车队,进行融合,车队的速度就是车队中最慢的车辆的速度。那么很明显,此处应该是cars[j]
的速度较慢,所以后面的车撞上前面的车,最后的车队速度一定是前面的车的速度,所以可以理解为cars[i]
消失了,cars[j]
状态不变。
因此,我们只需要关注一辆车的右边,不需要关注它的左边,它的左边对它没有任何影响。可以考虑从右往左遍历。
import java.util.Stack;
class Solution {
public double[] getCollisionTimes(int[][] cars) {
int n = cars.length;
double[] res = new double[n]; res[n-1] = -1.0;
Stack<Integer> stack = new Stack<>();
stack.push(n-1);
for(int i = n-2;i >= 0;i--) {
int[] curCar = cars[i];
while(stack.size() > 0) {
int topIndex = stack.peek();
// 前面一辆车的速度很快,追不上,可以等它消失后,再去追前面的车
if(curCar[1] <= cars[topIndex][1]) {
stack.pop();
} else {
// 前面一辆车的速度比当前这辆车要慢,可以追上
// 如果前面的车不会消失(融入车队)
if(res[topIndex] < 0) break;
// 如果前面的车会消失,那么需要计算能否在消失之前追上它
double maxDis = res[topIndex] * (curCar[1] - cars[topIndex][1]); //消失前能行驶的最长距离
if(maxDis >= (cars[topIndex][0]-curCar[0])) {
//能追上
break;
} else {
//消失前没法追上,只能让它消失,去找前面的车
stack.pop();
}
}
}
if(stack.size() == 0) {
res[i] = -1;
} else {
double t = (1.0 * (cars[stack.peek()][0]-curCar[0])) / (1.0*(curCar[1] - cars[stack.peek()][1]));
res[i] = t;
}
stack.push(i);
}
return res;
}
}