Easy
题目描述
给你一个大小为 n 的 0 索引数组 nums,数组由非负整数组成。
你需要对这个数组执行 n - 1 次操作,其中第 i 次操作(从 0 开始索引)中,你需要对 nums 的第 i 个元素执行以下操作:
- 如果
nums[i] == nums[i + 1],则将nums[i]乘以 2 并将nums[i + 1]设为 0。否则,跳过此操作。
在执行所有操作后,将所有 0 移动到数组末尾。
- 例如,数组
[1,0,2,0,0,1]在将所有 0 移动到末尾后,变为[1,2,1,0,0,0]。
返回结果数组。
注意操作是按顺序执行的,不是同时执行。
示例 1:
输入:nums = [1,2,2,1,1,0]
输出:[1,4,2,0,0,0]
解释:我们执行以下操作:
- i = 0:nums[0] 和 nums[1] 不相等,跳过此操作。
- i = 1:nums[1] 和 nums[2] 相等,将 nums[1] 乘以 2,将 nums[2] 改为 0。数组变为 [1,4,0,1,1,0]。
- i = 2:nums[2] 和 nums[3] 不相等,跳过此操作。
- i = 3:nums[3] 和 nums[4] 相等,将 nums[3] 乘以 2,将 nums[4] 改为 0。数组变为 [1,4,0,2,0,0]。
- i = 4:nums[4] 和 nums[5] 相等,将 nums[4] 乘以 2,将 nums[5] 改为 0。数组变为 [1,4,0,2,0,0]。
然后将 0 移动到末尾,得到数组 [1,4,2,0,0,0]。
示例 2:
输入:nums = [0,1]
输出:[1,0]
解释:无法应用任何操作,只需将 0 移动到末尾。
提示:
2 <= nums.length <= 20000 <= nums[i] <= 1000
解题思路
这道题需要分两个阶段来解决:
解题思路
第一阶段:执行合并操作
我们需要从左到右遍历数组,对于每个位置 i(0 ≤ i < n-1),检查 nums[i] 是否等于 nums[i+1]:
- 如果相等,将
nums[i]乘以 2,将nums[i+1]置为 0 - 如果不相等,跳过操作
这一步的关键是要按顺序执行,因为前面的操作可能会影响后面的判断。
第二阶段:移动零到末尾 执行完所有合并操作后,需要将数组中的所有 0 移动到末尾,保持非零元素的相对顺序不变。
有两种常见的实现方法:
- 双指针方法(推荐):使用一个指针记录下一个非零元素应该放置的位置,遍历数组将非零元素前移,最后将剩余位置填充为 0。
- 新数组方法:创建新数组,先放入所有非零元素,再填充 0。
双指针方法更优,空间复杂度为 O(1),而且逻辑清晰简洁。
代码实现
class Solution {
public:
vector<int> applyOperations(vector<int>& nums) {
int n = nums.size();
// 第一阶段:执行合并操作
for (int i = 0; i < n - 1; i++) {
if (nums[i] == nums[i + 1]) {
nums[i] *= 2;
nums[i + 1] = 0;
}
}
// 第二阶段:移动零到末尾
int left = 0;
for (int right = 0; right < n; right++) {
if (nums[right] != 0) {
nums[left++] = nums[right];
}
}
// 填充剩余位置为0
while (left < n) {
nums[left++] = 0;
}
return nums;
}
};
class Solution:
def applyOperations(self, nums: List[int]) -> List[int]:
n = len(nums)
# 第一阶段:执行合并操作
for i in range(n - 1):
if nums[i] == nums[i + 1]:
nums[i] *= 2
nums[i + 1] = 0
# 第二阶段:移动零到末尾
left = 0
for right in range(n):
if nums[right] != 0:
nums[left] = nums[right]
left += 1
# 填充剩余位置为0
while left < n:
nums[left] = 0
left += 1
return nums
public class Solution {
public int[] ApplyOperations(int[] nums) {
int n = nums.Length;
// 第一阶段:执行合并操作
for (int i = 0; i < n - 1; i++) {
if (nums[i] == nums[i + 1]) {
nums[i] *= 2;
nums[i + 1] = 0;
}
}
// 第二阶段:移动零到末尾
int left = 0;
for (int right = 0; right < n; right++) {
if (nums[right] != 0) {
nums[left++] = nums[right];
}
}
// 填充剩余位置为0
while (left < n) {
nums[left++] = 0;
}
return nums;
}
}
var applyOperations = function(nums) {
const n = nums.length;
// 第一阶段:执行合并操作
for (let i = 0; i < n - 1; i++) {
if (nums[i]
复杂度分析
| 复杂度类型 | 分析 |
|---|---|
| 时间复杂度 | O(n),需要遍历数组两次,每次都是线性时间 |
| 空间复杂度 | O(1),只使用了常数个额外变量,原地修改数组 |
相关题目
. Move Zeroes (Easy)