You are given a 0-indexed integer array nums. In one operation you can replace any element of the array with any two elements that sum to it.
For example, consider nums = [5,6,7]. In one operation, we can replace nums[1] with 2 and 4 and convert nums to [5,2,4,7].
Return the minimum number of operations to make an array that is sorted in non-decreasing order.
Example 1:
Input: nums = [3,9,3]
Output: 2
Explanation: Here are the steps to sort the array in non-decreasing order:
Example 2:
Input: nums = [1,2,3,4,5]
Output: 0
Explanation: The array is already in non-decreasing order. Therefore, we return 0.
Constraints:
听说是 google 的面试题
首先想到的应该是倒序处理这个题, 因为如果采用正序, 我们遇到任何一个 nums[i] < nums[i-1], 我们都要把前面 nums[…i]检查处理一遍, 会非常耗时。使用倒序每一步我们都可以确定当前最大的最小值, 我们只要把当前值拆分成小于等于当前最小值的数字就可以了, 然后从拆分出来的数字中找到最小值继续向下传递。
自己做的时候就想到这了, 然后下面就是要考虑拆分数字的策略了, 看下面的例子
[2, 2, 2, 2, 2, 2, 2, 10, 3]
因为 10 在 3 前面,又大于 3, 所以要进行拆分,因为拆分后的最大值不能大于 3, 所以理所当然的, 我们会想用 10 / 3, 拆分成[3, 3, 3, 1], 但是如果按这种拆分方法, 此时的最小值是 1, 继续向前走的话, 前面所有的 2 都需要拆分成[1, 1], 这显然不是最好的解。看到这, 我们肯定可以看出, 我们可以将 10 拆分成[3, 3, 2, 2], 这样的话前面所有 2 就都不用进行拆分了。
答案出来了, 但是过程怎么表达呢?
假设 prev 是上一步得出的最小值, 也就是需要将当前数字拆分成小于或等于 prev 的数字, num_of_pieces = (nums[i] / prev) + 1, 这里 num_of_pieces 就是要将当前数字拆分成不大于 prev 的数字时所能拆分的最少份数, 如果 nums[i]能被 prev 整除, 那末尾的+1 就要去掉, 然后我们将 nums[i] / num_of_pieces 就可以得到拆分成 num_of_pieces 份后最大化的最小值。
还是看上面的例子, num_of_pieces = (10 / 3) + 1, num_of_pieces = 4, next = 10 / 4, next = 2
num_of_pieces = 4 意味着我们要想将 10 拆分成都不大于 3 的数字, 最少要分 4 份
开始:
remain = 10
pieces = [0, 0, 0, 0]
第一步:
remain = 2
pieces = [2, 2, 2, 2]
第二步:
remain = 0
pieces = [3, 3, 2, 2]
impl Solution {
pub fn minimum_replacement(nums: Vec<i32>) -> i64 {
let mut prev = nums[nums.len() - 1] as i64;
let mut ans = 0;
for i in (0..nums.len() - 1).rev() {
let num_of_pieces =
nums[i] as i64 / prev + if nums[i] as i64 % prev == 0 { 0 } else { 1 };
ans += num_of_pieces - 1;
prev = nums[i] as i64 / num_of_pieces;
}
ans
}
}