执行操作使所有数组元素变为零
我尝试了解决这个LeetCode的问题,结果我的方案通过了1017个测试用例中的1026个。剩下的那些失败的测试用例是因为超时,而不是我的方案错误。所以我在想,有没有人能给我一些优化的方法。我知道问题出在我每次都要在子列表中找到最小值。我觉得可以用一些前缀和的逻辑来优化,但我不太确定该怎么把它引入我的方法中。
这是题目:
给你一个从0开始索引的整数数组nums和一个正整数k。
你可以对数组进行以下操作任意次数:
选择数组中任意大小为k的子数组,并将所有元素减1。如果你能让数组中的所有元素都变为0,就返回true,否则返回false。
子数组是数组中连续的非空部分。
例子1:
输入:nums = [2,2,3,1,1,0], k = 3 输出:true
解释:我们可以进行以下操作:
- 选择子数组[2,2,3]。结果数组变为nums = [1,1,2,1,1,0]。
- 选择子数组[2,1,1]。结果数组变为nums = [1,1,1,0,0,0]。
- 选择子数组[1,1,1]。结果数组变为nums = [0,0,0,0,0,0]。
例子2:
输入:nums = [1,3,1,1], k = 2 输出:false
解释:无法让所有数组元素都变为0。
这是我的代码:
def checkArray(self, nums: List[int], k: int) -> bool:
i, j = 0, k
while i + k <= len(nums):
sublist = nums[i:j] # Make a copy of the sublist
smallest = min(sublist)
for x in range(len(sublist)):
sublist[x] -= smallest # Modify the values in the sublist
if x > 0 and sublist[x] < sublist[x-1]:
return False
nums[i:j] = sublist # Assign the modified sublist back to the original list
i += 1
j += 1
return sum(nums) == 0
这是我的思路,方便大家理解我的方法:
我使用了滑动窗口。在每个窗口内,我们做了两件事:模拟应用操作以将元素减少到0,同时检查窗口是否有效。窗口有效的条件是,当前遍历的元素左边没有元素在模拟完成后仍然大于它。这是有道理的,因为如果左边的元素比它大,说明左边的元素在大小为k的窗口内无法减到0。这里的模拟是指,我们不需要不断地从窗口内的所有元素中减去1,直到最小值变为0,而是找到窗口内的最小元素,然后从窗口内的所有元素中减去这个最小值。这样做的结果是一样的,但效率更高。
1 个回答
我们可以采用一种贪心的方法:每当我们在向前遍历时遇到一个非零的元素,就把从这个元素开始的大小为 k
的整个范围内的值都减去这个元素的值。我们不需要在这个范围内寻找最小值;如果范围内有任何值小于左端点的值,那么就不可能把所有元素都变成0。为了快速进行范围更新,我们可以使用一个差分数组。
示例实现:
class Solution:
def checkArray(self, nums: List[int], k: int) -> bool:
diff = [0] * (len(nums) + 1)
for i, v in enumerate(nums):
if i: diff[i] += diff[i - 1]
v += diff[i]
if v < 0: return False
if v:
if i + k > len(nums): return False
diff[i] -= v
diff[i + k] += v
return True