Given two integer arrays arr1
and arr2
, return the minimum number of operations (possibly zero) needed to make arr1
strictly increasing.
In one operation, you can choose two indices 0 <= i < arr1.length
and 0 <= j < arr2.length
and do the assignment arr1[i] = arr2[j]
.
If there is no way to make arr1
strictly increasing, return -1
.
Example 1:
Input: arr1 = [1,5,3,6,7], arr2 = [1,3,2,4] Output: 1 Explanation: Replace5
with2
, thenarr1 = [1, 2, 3, 6, 7]
.
Example 2:
Input: arr1 = [1,5,3,6,7], arr2 = [4,3,1] Output: 2 Explanation: Replace5
with3
and then replace3
with4
.arr1 = [1, 3, 4, 6, 7]
.
Example 3:
Input: arr1 = [1,5,3,6,7], arr2 = [1,6,3,3]
Output: -1
Explanation: You can't make arr1
strictly increasing.
Constraints:
1 <= arr1.length, arr2.length <= 2000
0 <= arr1[i], arr2[i] <= 10^9
This problem asks to find the minimum number of operations needed to make arr1
strictly increasing by replacing elements of arr1
with elements from arr2
. The solution uses dynamic programming.
Preprocessing arr2
: Sort arr2
and remove duplicate elements. This optimization significantly speeds up the binary search in the later steps.
Dynamic Programming: We use a DP array f
where f[i]
represents the minimum number of operations needed to make the subarray arr1[0...i]
strictly increasing. We add sentinel values (-∞ and ∞) to the beginning and end of arr1
to handle base cases.
Transition: For each element arr1[i]
, we consider two possibilities:
arr1[i]
is greater than arr1[i-1]
, then we can keep arr1[i]
without any additional operation. In this case, f[i] = f[i-1]
.arr1[i]
is not greater than arr1[i-1]
, we need to replace arr1[i]
with a suitable element from arr2
. We find the smallest element in arr2
that is greater than arr1[i-1]
using binary search. Then, we consider replacing previous elements as well to minimize operations. We iterate through possible replacements of previous elements(from i-1
to max(0, i-m)
), where m
is the number of elements in arr2
that are greater than arr1[i-1]
. For each possible number of replacements k
, if the condition arr1[i-k-1] < arr2[j-k]
holds (where j
is the index of the found element in arr2
), we update f[i]
to be the minimum of f[i]
and f[i-k-1]+k
.Result: f[n-1]
(where n
is the length of arr1
) will contain the minimum number of operations to make the entire array strictly increasing. If f[n-1]
is still infinity, it means it's impossible to make arr1
strictly increasing, so we return -1.
arr1
and m is the length of arr2
after removing duplicates. The dominant factor is the nested loop that iterates through possible replacements. The binary search adds a log m factor.f
.import bisect
class Solution:
def makeArrayIncreasing(self, arr1: List[int], arr2: List[int]) -> int:
arr2.sort()
arr2 = list(dict.fromkeys(arr2)) #remove duplicates
arr = [-float('inf')] + arr1 + [float('inf')]
n = len(arr)
dp = [float('inf')] * n
dp[0] = 0
for i in range(1, n):
if arr[i - 1] < arr[i]:
dp[i] = dp[i - 1]
j = bisect.bisect_left(arr2, arr[i])
for k in range(1, min(i, j) + 1):
if arr[i - k - 1] < arr2[j - k]:
dp[i] = min(dp[i], dp[i - k - 1] + k)
return dp[n - 1] if dp[n - 1] != float('inf') else -1
The code in other languages (Java, C++, Go, TypeScript, C#) follows the same algorithm and logic, differing only in syntax and standard library functions. The core DP approach and complexity analysis remain the same across all implementations.