LeetCode Weekly Contest 369 Summary
Overview
This article is a summary of the contest. I don’t plan to discuss each problem in detail, but will provide general ideas. The point of this article is self-reflection and improvement.
After reviewing the contest, it is not so difficult. Here is a brief description of my performance on each problem:
- Problem 1: Simple simulation problem, an easy one.
- Problem 2: Not difficult, but requires consideration of multiple cases. Unfortunately, I didn’t think thoroughly, resulting in 3 WA 😒.
- Problem 3: a Medium-level DP problem. Initially struggled to come up with a solution, wasted time on the unsolved problem 4, but eventually solved it quickly 😋.
- Problem 4: Despite being a hard-level problem and not solved during the contest, the code only exceeded time limits. After the contest, I figured out an optimization method by myself. Note that the messy logic during coding led to 2 WA 😒.
I. Find the K-or of an Array
Problem Description:
You are given a 0-indexed integer array
nums
, and an integerk
.The K-or of
nums
is a non-negative integer that satisfies the following:
- The
ith
bit is set in the K-or if and only if there are at leastk
elements ofnums
in which biti
is set.Return the K-or of
nums
.Note that a bit
i
is set inx
if(2i AND x) == 2i
, whereAND
is the bitwiseAND
operator.Example 1:
1
2
3
4
5
6
7 Input: nums = [7,12,9,8,9,15], k = 4
Output: 9
Explanation: Bit 0 is set at nums[0], nums[2], nums[4], and nums[5].
Bit 1 is set at nums[0], and nums[5].
Bit 2 is set at nums[0], nums[1], and nums[5].
Bit 3 is set at nums[1], nums[2], nums[3], nums[4], and nums[5].
Only bits 0 and 3 are set in at least k elements of the array, and bits i >= 4 are not set in any of the array's elements. Hence, the answer is 2^0 + 2^3 = 9.Example 2:
1
2
3 Input: nums = [2,12,1,11,4,5], k = 6
Output: 0
Explanation: Since k == 6 == nums.length, the 6-or of the array is equal to the bitwise AND of all its elements. Hence, the answer is 2 AND 12 AND 1 AND 11 AND 4 AND 5 = 0.Example 3:
1
2
3 Input: nums = [10,8,5,9,11,6,8], k = 1
Output: 15
Explanation: Since k == 1, the 1-or of the array is equal to the bitwise OR of all its elements. Hence, the answer is 10 OR 8 OR 5 OR 9 OR 11 OR 6 OR 8 = 15.Constraints:
1 <= nums.length <= 50
0 <= nums[i] < 231
1 <= k <= nums.length
The problem description is a bit hard to understand. Combining it with examples during the contest was necessary for quick understanding.
Bitwise simulation:
1 | class Solution { |
Time complexity: $O(n)$
II. Minimum Equal Sum of Two Arrays After Replacing Zeros
Problem Description:
You are given two arrays
nums1
andnums2
consisting of positive integers.You have to replace all the
0
’s in both arrays with strictly positive integers such that the sum of elements of both arrays becomes equal.Return the minimum equal sum you can obtain, or
-1
if it is impossible.Example 1:
1
2
3
4
5
6 Input: nums1 = [3,2,0,1,0], nums2 = [6,5,0]
Output: 12
Explanation: We can replace 0's in the following way:
- Replace the two 0's in nums1 with the values 2 and 4. The resulting array is nums1 = [3,2,2,1,4].
- Replace the 0 in nums2 with the value 1. The resulting array is nums2 = [6,5,1].
Both arrays have an equal sum of 12. It can be shown that it is the minimum sum we can obtain.Example 2:
1
2
3 Input: nums1 = [2,0,2,0], nums2 = [1,4]
Output: -1
Explanation: It is impossible to make the sum of both arrays equal.Constraints:
1 <= nums1.length, nums2.length <= 105
0 <= nums1[i], nums2[i] <= 106
- If there are
k
zeros innums1
, its sum must increase by at leastk
after replacement. - If
nums1
has at least one zero, its sum after replacement can be any value greater thansum(nums1)
. - Similar for
nums2
.
Return type of the function is long
. Array length is at most $10^5$, elements are at most $10^6$, and the sum is at most $10^{11}$, exceeding the limit of a 32-bit integer, which reminds us that all the intermediate results should be stored in long
type. In fact, it is a common practice to replace int
with long
in coding contests to avoid integer overflow.
The key is to identify conditions where equality does not hold. A mistake in this aspect led to three WA:
1 | import java.util.Arrays; |
III. Minimum Increment Operations to Make Array Beautiful
Problem Description:
You are given a 0-indexed integer array
nums
having lengthn
, and an integerk
.You can perform the following increment operation any number of times (including zero):
- Choose an index
i
in the range[0, n - 1]
, and increasenums[i]
by1
.An array is considered beautiful if, for any subarray with a size of
3
or more, its maximum element is greater than or equal tok
.Return an integer denoting the minimum number of increment operations needed to make
nums
beautiful.A subarray is a contiguous non-empty sequence of elements within an array.
Example 1:
1
2
3
4
5
6
7
8
9
10 Input: nums = [2,3,0,0,2], k = 4
Output: 3
Explanation: We can perform the following increment operations to make nums beautiful:
Choose index i = 1 and increase nums[1] by 1 -> [2,4,0,0,2].
Choose index i = 4 and increase nums[4] by 1 -> [2,4,0,0,3].
Choose index i = 4 and increase nums[4] by 1 -> [2,4,0,0,4].
The subarrays with a size of 3 or more are: [2,4,0], [4,0,0], [0,0,4], [2,4,0,0], [4,0,0,4], [2,4,0,0,4].
In all the subarrays, the maximum element is equal to k = 4, so nums is now beautiful.
It can be shown that nums cannot be made beautiful with fewer than 3 increment operations.
Hence, the answer is 3.Example 2:
1
2
3
4
5
6
7
8
9 Input: nums = [0,1,3,3], k = 5
Output: 2
Explanation: We can perform the following increment operations to make nums beautiful:
Choose index i = 2 and increase nums[2] by 1 -> [0,1,4,3].
Choose index i = 2 and increase nums[2] by 1 -> [0,1,5,3].
The subarrays with a size of 3 or more are: [0,1,5], [1,5,3], [0,1,5,3].
In all the subarrays, the maximum element is equal to k = 5, so nums is now beautiful.
It can be shown that nums cannot be made beautiful with fewer than 2 increment operations.
Hence, the answer is 2.Example 3:
1
2
3
4
5 Input: nums = [1,1,2], k = 1
Output: 0
Explanation: The only subarray with a size of 3 or more in this example is [1,1,2].
The maximum element, 2, is already greater than k = 1, so we don't need any increment operation.
Hence, the answer is 0.Constraints:
3 <= n == nums.length <= 105
0 <= nums[i] <= 109
0 <= k <= 109
An array is considered beautiful if, for any subarray with a size of
3
or more, its maximum element is greater than or equal tok
.
This condition is equivalent to having every subarray of length 3 with a maximum element $\ge k$.
Obviously, we should try to ensure that in every three consecutive elements, at least one element is $\ge k$. However, it is unclear which elements should be increased to $k$. To address this, let’s use DP.
1️⃣DP definition: dp[i]
: the minimum increment operations to make nums[0:i]
a beautiful array and nums[i]
$\ge k$. — Here are three bold points.
If nums[i]
$\ge k$, then nums[i - 2 : i]
forms a subarray of length 3 that can be covered, satisfying the condition for being a beautiful array. This coverage simultaneously indicates that we need to ensure nums[0:(i-3)]
is also a beautiful array to make nums[0:i]
a beautiful array. Results from dp[i - 3]
, dp[i - 2]
, and dp[i - 1]
all satisfy this requirement; thus, we take the minimum value in them:
2️⃣Recurrence relation: $dp[i] = \max\set{0,k-nums[i]} + \min\set{dp[i - 1], dp[i - 2], dp[i - 3]}$
3️⃣Answer: Choose the minimum value among dp[n - 3]
, dp[n - 2]
, and dp[n - 1]
, all of which can guarantee nums
being a beautiful array by DP definition.
1 | import java.util.Arrays; |
IV. Maximum Points After Collecting Coins From All Nodes
Problem Description:
There exists an undirected tree rooted at node
0
withn
nodes labeled from0
ton - 1
. You are given a 2D integer arrayedges
of lengthn - 1
, whereedges[i] = [ai, bi]
indicates that there is an edge between nodesai
andbi
in the tree. You are also given a 0-indexed arraycoins
of sizen
wherecoins[i]
indicates the number of coins in the vertexi
, and an integerk
.Starting from the root, you have to collect all the coins such that the coins at a node can only be collected if the coins of its ancestors have been already collected.
Coins at
nodei
can be collected in one of the following ways:
- Collect all the coins, but you will get
coins[i] - k
points. Ifcoins[i] - k
is negative then you will loseabs(coins[i] - k)
points.- Collect all the coins, but you will get
floor(coins[i] / 2)
points. If this way is used, then for all thenodej
present in the subtree ofnodei
,coins[j]
will get reduced tofloor(coins[j] / 2)
.Return the maximum points you can get after collecting the coins from all the tree nodes.
Example 1:
1
2
3
4
5
6
7
8 Input: edges = [[0,1],[1,2],[2,3]], coins = [10,10,3,3], k = 5
Output: 11
Explanation:
Collect all the coins from node 0 using the first way. Total points = 10 - 5 = 5.
Collect all the coins from node 1 using the first way. Total points = 5 + (10 - 5) = 10.
Collect all the coins from node 2 using the second way so coins left at node 3 will be floor(3 / 2) = 1. Total points = 10 + floor(3 / 2) = 11.
Collect all the coins from node 3 using the second way. Total points = 11 + floor(1 / 2) = 11.
It can be shown that the maximum points we can get after collecting coins from all the nodes is 11.Example 2:
1
2
3
4 Input: edges = [[0,1],[0,2]], coins = [8,4,4], k = 0
Output: 16
Explanation:
Coins will be collected from all the nodes using the first way. Therefore, total points = (8 - 0) + (4 - 0) + (4 - 0) = 16.Constraints:
n == coins.length
2 <= n <= 105
0 <= coins[i] <= 104
edges.length == n - 1
0 <= edges[i][0], edges[i][1] < n
0 <= k <= 104
1️⃣Build the tree. It’s essentially building a graph, and we need to perform DFS starting from node 0 to simulate tree traversal.
2️⃣There are two ways to collect coins (the problem is intentionally written in complicated words, requiring simplification):
- Option 1: Currently-collected coins plus
coins[i] - k
(regardless of sign). - Option 2:
floor(coins[i] / 2)
is essentially integer division, we should optimize the division using bitwise operation i.e.,coins[i] >> 1
. Bitwise operation also has the advantage that if the current node has $k$ ancestors choosing Option 2, then the coin count for that node iscoins[i] >> k
, avoiding the time cost of computing $2^k$ and division by $2^k$.
Based on these two options, we can write a recursive function for pre-order traversal:
1 | /** |
Up to this point, I had written the code during the contest but still encountered a timeout. Later, I came up with the following optimization ideas:
3️⃣ $\forall i, coins[i] \le 10^4$, and $\log_2(10^4) \approx 13.8$. Thus, as long as the ancestors of the current subtree have chosen Option 2 at least 14 times, the coin count for all nodes in this subtree will continuously halve to 0.
This is basically a pruning technique, and we check it at the beginning of the recur
function:
1 | if (half >= 14) return 0; |
4️⃣Speaking of recursion, we think about divide and conquer paradigms, which then lead to thoughts about DP paradigms. What is the difference between the two? — DP reuses results of subproblems, making it more efficient.
Although the process of traversing the tree cannot be written as an iteration, we can use a map to cache results of subproblems: the key is (nodes[i], half)
, and the value is the number of collected coins.
1 | private final HashMap<Node, HashMap<Long, Long>> dpMap = new HashMap<>(); |
With these two optimization steps, the code successfully passed:
1 | import java.util.ArrayList; |