杂碎算法题
移动零
题目
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
输入: nums = [0,1,0,3,12]输出: [1,3,12,0,0]
示例 2:
输入: nums = [0]输出: [0]
提示:
-
1 <= nums.length <= 10(4) -
-2(31) <= nums[i] <= 2(31) - 1
进阶:你能尽量减少完成的操作次数吗?
题目思路
核心思想:双“指针”(此指针的意思为为数组下标)
题目代码
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int dest=-1,cur=0;
for(int i=0;i<nums.size();i++){
if(nums[cur]==0) cur++;
else{
swap(nums[dest+1],nums[cur]);
dest++;
cur++;
}
}
}
};
#include <bits/stdc++.h>
using namespace std;
int main(){
int x;
vector<int> a;
while(scanf("%d",&x)!=EOF){
a.push_back(x);
}
int dest=-1,cur=0;
for(int i=0;i<a.size();i++){
if(a[cur]==0) cur++;
else{
swap(a[dest+1],a[cur]);
dest++;
cur++;
}
}
for(int i=0;i<a.size();i++){
cout<<a[i];
if(i!=a.size()-1) cout<<" ";
}
return 0;
}
复写零
题目
给你一个长度固定的整数数组 arr ,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。
注意:请不要在超过该数组长度的位置写入元素。请对输入的数组 就地 进行上述修改,不要从函数返回任何东西。
示例 1:
输入:arr = [1,0,2,3,0,4,5,0]
输出:[1,0,0,2,3,0,0,4]
解释:调用函数后,输入的数组将被修改为:[1,0,0,2,3,0,0,4]
示例 2:
输入:arr = [1,2,3]
输出:[1,2,3]
解释:调用函数后,输入的数组将被修改为:[1,2,3]
提示:
-
1 <= arr.length <= 10(4) -
0 <= arr[i] <= 9
代码一:
#include <bits/stdc++.h>
using namespace std;
int main(){
int x;
vector<int> a;
while(cin>>x){
a.push_back(x);
}
int n=a.size();
for(int i=0;i<a.size();i++){
if(a[i]==0){
a.insert(a.begin()+i,0);
i++;
}
}
for(int i=0;i<n;i++){
cout<<a[i]<<" ";
}
return 0;
}
题目思路
-
用双指针,从前往后?从后往前?
- 从前往后,会覆盖掉掉原有的值
![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传]()
-
考虑从后向前
-
怎么把两个指针移动后后面呢?(第一步)
-
1.看cur位置的值
-
不是0——dest后移一位
-
是0——dest后移两位
-
-
2.判断dest是否到最后
-
是——结束,此时cur指向规定长度内最后一位有值的数字
-
不是——cur++
-
-
-
判断dest是否出界(第1.5步)
-
如果出界:
-
a[n-1]=0;
-
dest-=2;
-
cur–;
-
-
-
从后向前操作(第二步)
-
cur位置非0——cur的值赋值到dest位置
- 两个指针各自向前一位
-
cur位置为——dest位置为0,向前一位,然后再赋值为0
- cur–
-
-
题目代码
class Solution {
public:
void duplicateZeros(vector<int>& arr) {
int cur=0,dest=-1;
int n=arr.size();
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;
}
while(cur>=0){
if(arr[cur]){
arr[dest--]=arr[cur--];
}
else{
arr[dest--]=0;
arr[dest--]=0;
cur--;
}
}
}
};
#include <bits/stdc++.h>
using namespace std;
int main(){
int x;
vector<int> a;
while(cin>>x){
a.push_back(x);
}
int cur=0,dest=-1;
int n=a.size();
//1.指针后移
while(cur<n){
if(a[cur]) dest++;
else dest+=2;
if(dest>=n-1) break;
cur++;
}
//2.越界判断
if(dest==n){
a[n-1]=0;
dest-=2;
cur--;
}
//3.从后向前操作
while(cur>=0){
if(a[cur]) a[dest--]=a[cur--];
else{
a[dest--]=0;
a[dest--]=0;
cur--;
}
}
for(int i=0;i<n;i++){
cout<<a[i];
if(i!=n-1) cout<<" ";
}
return 0;
}
变式
如果复写n次呢?
现在考虑更一般的情况:如果题目要求将每个零复写 n 次(即每个零变成 n+1 个零,包括原始的那个零),思路需要做以下调整:
调整后的思路
-
第一步:指针后移阶段
-
如果 cur 位置的值不是 0,dest 后移 1 位(非零元素仍占 1 个位置)。
-
如果 cur 位置的值是 0,dest 后移 (n+1) 位(因为每个零要复写 n 次,加上原始的 1 个零,共 n+1 个位置)。
-
当 dest 达到或超过 n-1 时,停止遍历。
-
-
第1.5步:越界判断
-
如果 dest 等于 n:
-
将 a[n-1] 设置为 0(占用最后一个位置)。
-
dest 回退 (n+1) 位(因为一个零占用 n+1 个位置)。
-
cur 回退 1 位。
-
-
-
第二步:从后向前操作
-
如果 cur 位置的值不是 0,将 a[cur] 赋值给 a[dest],dest 和 cur 各向前移动 1 位。
-
如果 cur 位置的值是 0,从 dest 开始的 (n+1) 个位置都赋值为 0,dest 向前移动 (n+1) 位,cur 向前移动 1 位。
-
关键变化
-
空间需求增加:每个零从占用 2 个位置变为 (n+1) 个位置,因此 dest 的移动步幅和填充范围都需要根据 n 调整。
-
代码调整:
-
指针后移时,dest += 2 改为 dest += (n+1)。
-
越界时,dest -= 2 改为 dest -= (n+1)。
-
填充时,从赋值 2 个零改为赋值 (n+1) 个零。
-
#include <bits/stdc++.h>
using namespace std;
int main() {
int x, n;
vector<int> a;
cin >> n; // 输入复写次数 n
while (cin >> x) {
a.push_back(x);
}
int cur = 0, dest = -1;
int m = a.size();
// 1. 指针后移
while (cur < m) {
if (a[cur]) dest++;
else dest += (n + 1);
if (dest >= m - 1) break;
cur++;
}
// 2. 越界判断
if (dest == m) {
a[m-1] = 0;
dest -= (n + 1);
cur--;
}
// 3. 从后向前操作
while (cur >= 0) {
if (a[cur]) a[dest--] = a[cur--];
else {
for (int i = 0; i <= n; i++) {
a[dest--] = 0;
}
cur--;
}
}
// 输出结果
for (int i = 0; i < m; i++) {
cout << a[i];
if (i != m - 1) cout << " ";
}
return 0;
}
快乐数
题目
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」 定义为:
-
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
-
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
-
如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n 是 快乐数 就返回 true ;不是,则返回 false 。
示例 1:
输入: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
示例 2:
输入:n = 2
输出:false
提示:
1 <= n <= 2(31) - 1


浙公网安备 33010602011771号