1089.复写0

算法原理
解法双指针算法:
1.先找到最后一个复写的数;
这里同样也可以使用双指针算法
初始化
根据cur遇到的值来选择dest的移动步数,当dest到数组末尾时,cur所在位置就是最后一个复写的数

注意一下可能出现的越界情况
2.之后从后向前完成复写操作;
遇到非零数就正常拷贝复写,遇到零就复写拷贝两次
cpp
1class Solution
2 {
3public:
4 void duplicateZeros(vector<int>& arr)
5 {
6 //先找到最后一个复写数
7 int cur = 0,dest = -1,n = arr.size();
8 while(cur < n )
9 {
10 if(arr[cur])
11 {
12 dest++;
13 }
14 else
15 {
16 dest += 2;
17 }
18 if(dest >= n-1)
19 {
20 break;
21 }
22 cur++;
23 }
24 //处理边界情况
25 if(dest == n)
26 {
27 arr[n-1] = 0;
28 cur--;dest -=2;
29 }
30 //从后向前完成复写操作
31 while(cur >= 0)
32 {
33 if(arr[cur])
34 {
35 arr[dest] = arr[cur];
36 dest--;
37 cur--;
38 }
39 else
40 {
41 arr[dest--] = 0;
42 arr[dest--] = 0;
43 cur--;
44 }
45 }
46 }
47};
202.快乐数

算法原理:
这个类似约瑟夫环,由题目可知这个会是一个循环,就代表一个数无论从哪里开始,走多少步,最后一定会进入一个循环,这个时候就可以使用快慢指针,一个数在前一个数在后,一个一次走一步另一个一次走两步,这两个数一定会相遇,相遇时有两种情况,情况一:快指针在1处循环,慢指针追上,也在1处循环,情况二:快指针走过一遍循环,追上慢指针,那我们就可以在相遇处判断是否为1来输出结果
cpp
class Solution
{
public:
int nsum(int n)
{
int sum =0;
int ret = 0;
while(n)
{
ret = n%10;
sum += ret*ret;
n = n/10;
}
return sum;
}
bool isHappy(int n)
{
int slow = n, fast = nsum(n);
while(slow != fast)
{
slow = nsum(slow);
fast = nsum(nsum(fast));
}
return slow == 1;
}
};
15,三数之和

算法原理:
解法一:排序+暴力+set去重
就是先排序,然后进行三次遍历,然后使用set容器去重
解法二:排序+双指针
首先先进行排序,然后从左到0依次固定数,然后再右边区间内进行双指针算法找到固定数的相反数
1.去重:当找到一种结果后两个指针都要跳过重复元素,使用完一次双指针后,固定的数也要去重
注意指针越界问题
2.不漏:找到一种结果后,不要停,缩小区间,继续寻找
cpp
1class Solution {
2public:
3 vector<vector<int>> threeSum(vector<int>& nums) {
4 vector<vector<int>> ret;
5 sort(nums.begin(),nums.end());
6 int n = nums.size();
7 for(int i = 0; i < n;)
8 {
9 if(nums[i] > 0)
10 {
11 break;
12 }
13 int left = i+1, right = n-1;
14 while(left < right)
15 {
16 if(left < right && nums[left] + nums[right] > -nums[i])
17 right--;
18 else if( left < right && nums[left] + nums[right] < -nums[i])
19 left++;
20 else{
21 ret.push_back({nums[i],nums[left],nums[right]});
22 right--;
23 left++;
24 while(left<right && nums[right] == nums[right+1])
25 {
26 right--;
27 }
28 while(left < right && nums[left] == nums[left-1])
29 {
30 left++;
31 }
32 }
33 }
34 while(i+1 < n && nums[i] == nums[i+1])
35 {
36 i++;
37 }
38 i++;
39 }
40 return ret;
41 }
42};
18.四数之和

算法原理:
解法一:排序+暴力枚举+set去重
解法二:排序+双指针
1.依次固定一个数a;
2.在a后面的区间内,利用"三数之和"找到三个数,使这三个数的和等于target - a即可
{
1.在前面的基础上,依次固定一个数b;
2.在b后面区间内,利用"双指针"找到两个数,使这两个数的和等于target-a-b
}(嵌套解法)
cpp
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> ret;
//1.排序
sort(nums.begin(),nums.end());
//2.利用双指针解决问题
int n = nums.size();
for(int i =0; i <n;)//固定数a
{
//利用三数之和解决问题
for(int j = i+1; j <n;)//固定数b
{
//双指针解法
int left = j+1,right = n-1;
long long aim = (long long)target -nums[i] - nums[j];
while(left < right)
{
int sum = nums[left] + nums[right];
if(sum< aim)left++;
else if( sum > aim)right--;
else
{
ret.push_back({nums[i],nums[j],nums[left],nums[right]});
left++;
right--;
//去重一
while(left < right && nums[left] == nums[left-1])
left++;
while(left < right&& nums[right] == nums[right+1])
right--;
}
}
//去重二
j++;
while(j < n && nums[j] == nums[j-1])
j++;
}
//去重三
i++;
while(i < n&& nums[i] == nums[i-1])
i++;
}
return ret;
}
};