LeetCode双周赛110
A题
代码:
public int accountBalanceAfterPurchase(int purchaseAmount) {
int t = 100 - (purchaseAmount / 10) * 10;
purchaseAmount %= 10;
if (purchaseAmount >= 5) {
t -= 10;
}
return t;
}
B题
两两链表插入一个最大公约数节点
代码:
public ListNode insertGreatestCommonDivisors(ListNode head) {
if (head.next != null) {
var cur = head.next;
merge(head, cur);
insertGreatestCommonDivisors(cur);
}
return head;
}
public int f(int x, int y) {
if (y == 0) {
return x;
}
return f(y, x % y);
}
private void merge(ListNode pre, ListNode next) {
int value = f(pre.val, next.val);
ListNode node = new ListNode(value);
pre.next = node;
node.next = next;
}
C题
给你一个下标从 0 开始长度为 n
的数组 nums
。
每一秒,你可以对数组执行以下操作:
- 对于范围在
[0, n - 1]
内的每一个下标i
,将nums[i]
替换成nums[i]
,nums[(i - 1 + n) % n]
或者nums[(i + 1) % n]
三者之一。
注意,所有元素会被同时替换。
请你返回将数组 nums
中所有元素变成相等元素所需要的 最少 秒数。
思路:本质上就是找出每个同源元素分割的所有区间,求出区间的最大值。
代码:
public int minimumSeconds(List<Integer> nums) {
Map<Integer, List<Integer>> map = new HashMap<>();
int n = nums.size() - 1;
for (int i = 0; i < nums.size(); i++) {
map.computeIfAbsent(nums.get(i), a -> new ArrayList<>()).add(i);
}
int mn = Integer.MAX_VALUE;
for (var list : map.values()) {
int len = list.get(0) + (n - list.get(list.size() - 1));
len = (len + 1) >> 1;
int ans = len;
for (int i = 1; i < list.size(); i++) {
len = list.get(i) - list.get(i - 1) - 1;
len = (len + 1) >> 1;
ans = Math.max(len, ans);
}
mn = Math.min(ans, mn);
}
return mn;
}
D题
给你两个长度相等下标从 0 开始的整数数组 nums1
和 nums2
。每一秒,对于所有下标 0 <= i < nums1.length
,nums1[i]
的值都增加 nums2[i]
。操作 完成后 ,你可以进行如下操作:
- 选择任一满足
0 <= i < nums1.length
的下标i
,并使nums1[i] = 0
。
同时给你一个整数 x
。
请你返回使 nums1
中所有元素之和 小于等于 x
所需要的 最少 时间,如果无法实现,那么返回 -1
。
思路:首先我们要明白元素之和最小的最优解是数组nums1最多每个元素操作一次的情况下达成,也就是最多操作n次,又因为每次操作的收益都是正向收益,所以每一秒都应当进行依次操作,所以假设最优解为t,则t<=n;
明白这个结论之后,我们可以枚举0 ~ n秒,获得每次都执行操作所能得到的一个最大收益。
我们现在来探讨收益,对于每一秒j来说,我们将一个元素i置为0,则收益是nums1[i] + nums2[i] * j,nums1[i]是一个固定值,nums2[i] * j随着j的增长逐渐增大,所以我们对于nums2进行一个从小到大的排序,因为nums2单调递增,所以选择删除的时间也应该是单调递增的,题目要求也就变成了从数组中选长度为j的子数组,求子数组的最大收益,也就是一个简单的dp题。
代码如下:
class Solution {
public int minimumTime(List<Integer> nums1, List<Integer> nums2, int x) {
// 第x次操作 价值为 nums1[i] + j * nums2[i]
int len = nums1.size();
long sum1 = 0L, sum2 = 0L;
Integer[] ids = new Integer[len];
for (int i = 0; i < len; i++) {
sum1 += nums1.get(i);
sum2 += nums2.get(i);
ids[i] = i;
}
Arrays.sort(ids, Comparator.comparingInt(nums2::get));
var dp = new long[len][len + 1];
for (int i = 0; i < len; i++) {
if (i == 0) {
dp[0][1] = nums1.get(ids[0]) + nums2.get(ids[0]);
continue;
}
for (int j = 1; j <= i + 1; j++) {
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - 1] + nums1.get(ids[i]) + (long) nums2.get(ids[i]) * j);
}
}
for (int i = 0; i <= len; i++) {
long sum = sum1 + i * sum2;
sum -= dp[len - 1][i];
if (sum <= x) {
return i;
}
}
return -1;
}
}