题目
题目链接
复写零
看到这道题的第一眼,就会感觉,太简单了,但不要忽略题目的一个要求,要就地操作,如果不就地操作,直接遍历一遍将结果写到另外一个数组就完成了。
算法原理
暴力枚举
从头到尾模拟一遍,如果找到0则先让0后的数整体往后挪一位,然后增加一位0,注意这个新增的0不要再计算!如此反复,最后跑到末尾即可!
class Solution {
public:
void duplicateZeros(vector<int>& arr) {
int n = arr.size() - 1;
for (int i = 0; i <= n; i++) {
if (arr[i] == 0 && i + 1 <= n) {
for (int j = n; j - 1 > i; j--) {
arr[j] = arr[j - 1];
}
arr[++i] = 0;
}
}
}
};
在最坏的情况下,全是0,那么这个时候的时间复杂度就是O(n^2)
双指针
定义两个指针
dest:表示最终的位置
cur:从左往右扫描数组,遍历数组
先模拟异地操作,然后由异地操作优化未就地操作
从前往后原地操作,当走到0的时候,0后面的数字就被覆盖了
这时候就要考虑一下,既然异地当复写0的时候最后几个元素是会被淘汰掉的,那么从后面的位置开始向前复写就可以了,由上面的异地模拟可以得出[1,0,0,3,0,4,5,0]的4这个位置就是最后一个复写的数字,
我们再从后往前模拟一遍原地操作
编写代码逻辑如下
1.先判断cur位置的值
2.决定dest向后移动一步或两步
3.判断一下dest是否已经到结束为止
3.cur++
这里有一个特殊情况
代码
class Solution {
public:
void duplicateZeros(vector<int>& arr) {
int cur = 0, dest = -1, n = arr.size();
// 找到cur和dest的最后位置
while (cur < n) {
if (arr[cur])
dest++;
else
dest += 2;
if (dest >= n - 1)
break;
cur++;
}
if (dest == n) {
arr[n - 1] = 0;
cur--;
dest -= 2;
}
// 从后往前开始复写0
while (cur >= 0) {
if (arr[cur])
arr[dest--] = arr[cur--];
else {
arr[dest--] = 0;
arr[dest--] = 0;
cur--;
}
}
}
};
相比暴力解法,这里的时间复杂度只有O(n)