刷题|数组移动元素

博客 动态
0 133
羽尘
羽尘 2023-05-03 20:54:46
悬赏:0 积分 收藏

刷题 | 数组移动元素

题目描述

LeetCode.283. 移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

示例 1:

输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]

示例 2:

输入: nums = [0]
输出: [0]

提示:

1 <= nums.length <= 104
-231 <= nums[i] <= 231 - 1


解法1

算法思想:

  1. 创建一个数组tmps用于存储nums中所有的非零元素(按原有顺序存储),遍历nums,将非零元素存于tmps中。
  2. 遍历tmps,将tmps中元素覆盖nums元素(从0号下标开始依次覆盖)。
  3. 将nums剩余位置元素置零。

时间复杂度=O(n)

空间复杂度=O(n)

代码实现:

#include <iostream>
#include <vector>

using namespace std;

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        vector<int> tmps;
        int i;
        for(i = 0; i < nums.size(); i++){
            if(nums[i] != 0){
                tmps.push_back(nums[i]);
            }
        }
        for(i = 0; i < tmps.size(); i++){
            nums[i] = tmps[i];
        }
        for(; i < nums.size(); i++){
            nums[i] = 0;
        }
    }
};

int main()
{
   int arr[] = {0, 1, 0, 3, 12};
   vector<int> vec(arr, arr + sizeof(arr) / sizeof(int));
   Solution().moveZeroes(vec);
   for(int i = 0; i < vec.size(); i++){
    cout << vec[i] << " ";
   }
   cout << endl;
   system("pause");
   return 0;
}

运行效果:

1 3 12 0 0

解法2

算法思想:

原地操作,不开辟新的内存空间

  1. 声明两个指针i和k,i:用于遍历数组,k:保证[0...k)中保存所有当前已遍历过的所有非0元素;

    即:遍历完第i个元素后,[0...i]中所有非0元素都按照原有顺序排列再[0...k)中。

  2. 若当前元素nums[i]为0元素,忽略,继续向前遍历;

  3. 若当前元素nums[i]为非0元素,将该元素插入到nums[k]的位置,然后i++,k++;

  4. 重复上述操作,直至指针i遍历结束;

  5. 从位置k开始遍历数组,将元素值置零。

代码实现:

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int i, k = 0;
        for(i = 0; i < nums.size(); i++){
            if(nums[i] == 0){
                continue;
            }else{
                nums[k++] = nums[i];
            }
        }
        for(i = k; i < nums.size(); i++){
            nums[i] = 0;
        }
    }
};

相当于把数组nums分成左右两部分:

  • 左部分:已处理元素集合,存储数组中已经处理完毕的非零元素(处理完毕即元素均为非0元素且按原有顺序排列),左右边界为[0...k),初始时k=0代表左部分为空;
  • 右部分:待处理元素集合,左右边界为[k...nums.size()-1],初始时k=0代表整个数组。

解法3:

算法思想:

在解法2的基础上进一步优化,去掉解法2最后一步将数组剩余元素置零的操作。

  1. 声明两个指针i和k,i:用于遍历数组,k:保证[0...k)中保存所有当前已遍历过的所有非0元素;

    即:遍历完第i个元素后,[0...i]中所有非0元素都按照原有顺序排列再[0...k)中。

  2. 若当前元素nums[i]为0元素,忽略,继续向前遍历;

  3. 若当前元素nums[i]为非0元素,将该元素与nums[k]对应元素交换位置,然后i++,k++;

  4. 重复上述操作,直至指针i遍历结束;

代码实现:

class Solution {
public:
    void swap(int &a, int &b){
        int tmp = a;
        a = b;
        b = tmp;
    }
    void moveZeroes(vector<int>& nums) {
        int i, k = 0;
        for(i = k; i < nums.size(); i++){
            if(nums[i] == 0){
                continue;
            }else{
                swap(nums[k++], nums[i]);
            }
        }
    }
};

进一步优化:

若数组nums全是非零元素,按照上述代码,每个元素(均为非0元素)都会和自己执行一次交换,耗时。

class Solution {
public:
    void swap(int &a, int &b){
        int tmp = a;
        a = b;
        b = tmp;
    }
    void moveZeroes(vector<int>& nums) {
        int i, k = 0;
        for(i = k; i < nums.size(); i++){
            if(nums[i] == 0){
                continue;
            }else{
                if(nums[k] == 0){
                    swap(nums[k++], nums[i]);
                }else{
                    k++;
                }
            }
        }
    }
};

相似题目

leetcode.27. 移除元素

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int k = 0;
        for(int i = k; i < nums.size(); i++){
            if(nums[i] != val){
                nums[k++] = nums[i];
            }
        }
        return k;
    }
};

leetcode.26. 删除有序数组中的重复项

/*
算法思想:
    声明指针k,将数组划分成两部分:nums[0...k)为已处理序列,nums[k...]为待处理序列,k初始时为0
    声明指针i遍历数组:
        1. 若已处理序列为空(即k==0),则将当前元素nums[i]插入到k位置,并执行k++;
        2. 若已处理序列非空,将当前元素nums[i]与已处理序列尾元素nums[k-1]比较:
            (1)若二者相等,忽略当前元素,继续遍历;
            (2)若二者不等,将当前元素nums[i]插入到k位置,并执行k++。
*/
class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int k = 0;
        for(int i = 0; i < nums.size(); i++){
            if(k == 0){
                nums[k++] = nums[i];
            }else{
                if(nums[i] != nums[k-1]){
                    nums[k++] = nums[i];
                }
            }
        }
        return k;
    }
};

leetcode.80. 删除有序数组中的重复项 II

将leetcode.26中的nums[i] != nums[k-1]改为nums[i] != nums[k-2]即可。

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int k = 0;
        for(int i = 0; i < nums.size(); i++){
            if(k == 0){
                nums[k++] = nums[i];
            }else{
                if(nums[i] != nums[k-2]){
                    nums[k++] = nums[i];
                }
            }
        }
        return k;
    }
};
posted @ 2023-05-03 20:37  就良同学  阅读(0)  评论(0编辑  收藏  举报
回帖
    羽尘

    羽尘 (王者 段位)

    2233 积分 (2)粉丝 (11)源码

     

    温馨提示

    亦奇源码

    最新会员