双指针算法
题目一:移动零
样例:
输入: nums = [0,1,0,3,12] 输出: [1,3,12,0,0]
题目解析: 给定一个数组,将 0 移动到末尾,不必考虑 0 的相对顺序,但是要保持非零元素的相对顺序。
如果不使用双指针,有很多解法。比如我们可以将所有的非零元素移动到最开始,但是移动一次就需要遍历一次,时间复杂度接近 O(N^2),这是暴力解法。那么如何使用双指针呢?
算法原理: 通过使用双指针,将数组划分为三个区域:
[0, dest]划分为非零元素的区域[dest, cur]划分为 0 元素的区域[cur, end]划分为还没有遍历的区域
这里实际上不是真正的指针,它们代表的只是形象地指向两个元素而已。这里的指针可以是一个数,可以是数组下标,也可以是任何能代替指向的东西。
定义两个下标 dest 和 cur,二者都是从 0 开始划分。cur 遍历数组,找到非零的元素,就赋值给 dest。dest 可以从 -1 开始,因为 cur 是从 0 开始的。找到了非零元素,dest++ 进行交换,cur 正常走即可。
算法编写:
class Solution {
public:
void moveZeroes(vector<int>& nums) {
for(int cur = 0, dest = -1; cur < nums.size(); cur++) {
if(nums[cur]) swap(nums[++dest], nums[cur]);
}
}
};
简单的分析一下时间复杂度吧,一次遍历,O(N)。如果暴力是平方,这优化得很不错。
题目链接:283. 移动零 - LeetCode
题目二:快乐数
样例:
输入: n = 19 输出: true 解释: 1^2 + 9^2 = 82; 8^2 + 2^2 = 68; 6^2 + 8^2 = 100; 1^2 + 0^2 + 0^2 = 1
题目解析: 快乐数的定义为将一个数多次等于该数上的每一位数字的平方相加,如果经过多次变化,数字可以变为 1,那么就是快乐数。但是如果是一直无限循环没有变成 1,那么该数就不是快乐数。对于这种题目就没有暴力解法,因为真要暴力的话很有可能套死循环出不去了。
算法原理: 我们不妨画图看看变化是怎么个事儿。 对于 19 来说,经过了 4 次变化就到 1。对于 2 来说,经过多次变化,出现了和第一次变化一样的值 4。
那么我们可不可以理解 2 在变化的时候出现了环,且数的变化出不了这个环,所以它不是快乐数。如果我们换个角度,19 变化的时候,是不是出现了一个环,环里面只有 1 呢?


