LeetCode刷题(C++)-数组篇

本文介绍了数组相关的算法问题,包括合并两个有序数组、删除有序数组中的重复项、移动零、二分查找、移除元素、有序数组的平方以及寻找长度最小的子数组等。每个问题都提供了详细的解题思路和代码实现,强调了边界处理和效率优化的重要性。
摘要由CSDN通过智能技术生成

数组

88.合并两个有序数组

思路:i,j两个索引,谁大放谁,从后往前放。如果是谁小放谁从头开始放的话,需要重新开辟一个数组保存排序结果,再copy到nums1中,否则会有部分nums1元素提前就被覆盖掉。

细节:边界问题

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        int i = m - 1, j = n - 1;
        for(int k = m + n - 1; k >= 0; k--){
            if(j < 0 || (i >= 0 && nums1[i] >= nums2[j])){
                nums1[k] = nums1[i];
                i--;
            }else{
                nums1[k] = nums2[j];
                j--;
            }
        }
    }
};

26.删除有序数组中的重复项(去重)

思路:遍历,与前面不一样的元素就可以单独拿出来,可以开辟一个新的容器装,也可以直接覆盖在原来的nums数组中,这样就省下了O(N)的开辟空间

细节:数组越界问题(考虑到有i-1)

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int n = 0;
        for(int i = 0; i < nums.size(); i++){
            if(i == 0 || nums[i] != nums[i - 1]){
                nums[n] = nums[i];
                n++;
            }
        }
        return n;
    }
};

283.移动零

思路:和上一题思路一样,看需要什么,上一题是需要和前一元素不同的元素,本题是需要不为0的元素。然后再在后面补0。

细节:忘记n++了

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

704 二分查找

左闭右闭区间写法:

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;
        while(left <= right){
            int middle = left + ((right-left)/2);
            if(nums[middle]>target){
                right = middle-1;
            }else if(nums[middle]<target){
                left = middle+1;
            }else{
                return middle;
            }
        }
        return -1;
    }
};

左闭右开区间写法:

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size();
        while(left < right){
            int middle = left + ((right-left)/2);
            if(nums[middle]>target){
                right = middle;
            }else if(nums[middle]<target){
                left = middle+1;
            }else{
                return middle;
            }
        }
        return -1;
    }
};

27.移除元素

其实就是要自己实现一个erase()

暴力解法:O(n^2)

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

双指针解法:O(n)

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

977.有序数组的平方

暴力法:先平方再排序,O(nlogn)

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        for(int i = 0; i < nums.size(); i++){
            nums[i] *= nums[i];
        }
        sort(nums.begin(),nums.end());
        return nums;
    }
};

双指针法:O(n)

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
       vector<int> result(nums.size(), 0);
       int k = nums.size() - 1;
       for(int i = 0, j = nums.size() - 1; i <= j; ){
           if(nums[i] * nums[i] < nums[j] * nums[j]){
               result[k--] = nums[j] * nums[j];
               j--;
           }
           else{
               result[k--] = nums[i] * nums[i];
               i++;
            }
       }
       return result;
    }
};

209.长度最小的子数组

暴力解法:O(n^2),两层for循环,可能会超时

注意:第二层循环找到了子串和>=target就可以break

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int result = INT32_MAX;
        int sum = 0;
        int subLength = 0;
        for(int i = 0; i < nums.size(); i++){
            sum = 0;
            for(int j = i; j < nums.size(); j++){
                sum += nums[j];
                if(sum >= target){
                    subLength = j - i + 1;
                    result =  result < subLength ? result : subLength;
                    break;
                }
            }
        }
        return result == INT32_MAX ? 0 : result;
    }
};

滑动窗口:O(n),精髓之处是不断改变起始位置,找到满足条件的最小子串

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
       int result = INT32_MAX;
       int sum = 0;
       int subLength = 0;
       int i = 0;//起始位置
       for(int j = 0; j < nums.size(); j++){
           sum += nums[j];
           while(sum >= target){
               subLength = (j - i + 1);
               result = result < subLength ? result : subLength;
               sum -= nums[i++];//不断变更子数组的起始位置
           }
       }
       return result == INT32_MAX ? 0 : result;
    }
};

59.螺旋矩阵②

一进循环深似海,从此offer是路人。边界处理问题,这里统一使用左闭右开的原则处理。

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        //左闭右开原则
        vector<vector<int>> res(n, vector<int>(n,0));
        int loop = n / 2;//循环圈数
        int startx = 0, starty = 0;//每一圈循环的起始位置
        int count = 1;//存放的数
        int i = 0, j = 0;//记录位置
        int offset = 1;//用于控制边界
        int mid = n / 2;//记录中间位置

        while(loop--){
            i = startx;
            j = starty;
            for(; j < n - offset; j++){
                res[i][j] = count++;
            }
            for(; i < n - offset; i++){
                res[i][j] = count++;
            }
            for(; j > starty; j--){
                res[i][j] = count++;
            }
            for(; i > startx; i--){
                res[i][j] = count++;
            }
            startx++;
            starty++;
            offset++;
        }
        if(n % 2 == 1){
            res[mid][mid] = count;
        }
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值