与数组相关的算法题

本文介绍了与一维数组相关的算法问题,包括二分查找、数组中移除元素的策略,以及有序数组的平方处理。在二分查找中强调了区间定义的关键点;在移除元素时探讨了暴力法和双指针法;有序数组的平方处理则通过双指针解决;最后讲解了长度最小的子数组和螺旋数组II的解题思路。
摘要由CSDN通过智能技术生成

一维数组空间是连续的,二维地址空间是多个连续的地址空间组成。因为其连续性,导致其不能随便删除元素,只能覆盖。数组类型的题目多出二分查找,双指针,滑动窗口,模拟行为等。 

​​​​​​1. 二分查找

1.1 思路

二分查找关键点在于对于区间的定义。主要有两种方式:左闭右闭、左闭右开。

在刷题过程中默认使用左闭右闭的方式,在这个过程中需要注意两点:

right = nums.size() - 1
if(nums[middle] > target){
    right = middle - 1
}

1.2 代码

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0, middle = 0;
        int right = nums.size() - 1; //使用左闭右闭的思路
        while(left <= right){
            middle = left + (right - left) / 2; //这样计算中间值在索引很大的时候不容易越界
            if(nums[middle] == target){
                return middle;
            }
            else if(nums[middle] < target){
                left = middle + 1;
            }
            else{
                right = middle - 1;
            }
        }
        return -1;
    }
};

2. 数组中的移除元素

2.1 思路

因为数组中的空间中的地址是连续的,不能随便删除,所以移除元素主要是通过覆盖完成的。该题有两个解决方案:

1、使用暴力法两次循环,一次循环遍历数组,第二次循环更新覆盖数组。

2、使用双指针。慢指针和快指针同时出发,当快指针遇到需要移除的元素时,独自往前走一步。否则两者同时往前走一步,且慢指针获得快指针的元素值,这样一来,就做到慢指针不断覆盖之前数组的值

快指针指向的是移除元素后的下一个元素

2.2 代码

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        if(nums.size() <= 0){
            return 0;
        }  
        int slowIndex = 0;
        for(int fastIndex = 0; fastIndex <= nums.size()-1; fastIndex++){
            if(val != nums[fastIndex]){
                nums[slowIndex++] = nums[fastIndex]; //原数组被不断覆盖
            }
        }
        return slowIndex;
    }
};

3. 有序数组的平方

3.1 思路

因为当数组中存在负数时,平方会变为整数,会使得乱序。

1、使用暴力解法,先平方,再排序。

2、使用双指针。数组两边数的平方一定比中间的数大,双指针指向两边,新建一个和原数组大小一样的数组,从尾端开始插入。注意最后一个元素。

3.2 代码

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        int beginIndex = 0, endIndex = nums.size()-1;
        vector<int> result(nums);
        int resIndex = endIndex;
        while(beginIndex <= endIndex){ //这里是为了处理最后一个元素
            if(pow(nums[beginIndex],2) >= pow(nums[endIndex],2)){ 
                result[resIndex--] = pow(nums[beginIndex],2);
                beginIndex++;
            }
            else{
                result[resIndex--] = pow(nums[endIndex],2);
                endIndex--;
            }
        }
        return result;
    }
};

4. 长度最小的子数组

4.1 思路 

1、使用双for循环暴力解法

2、使用滑动窗口,即双指针。快指针不断往前找大于s的数组子集,慢指针不断减小这个子集的大小

4.2 代码

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int resLength = INT32_MAX;
        int subLength = 0;
        int sum = 0;
        int lowIndex = 0;
        for(int fastIndex = 0; fastIndex <= nums.size()-1; fastIndex++){//快指针不断往前走找符合的子集
            sum += nums[fastIndex];
            while(sum >= target){
                subLength = fastIndex - lowIndex + 1;
                resLength = resLength < subLength ? resLength : subLength;
                sum -= nums[lowIndex++];
            }
        }
        return resLength == INT32_MAX ? 0 : resLength;
    }
};

 5. 螺旋数组II

5.1 思路

注意左闭右开的原则,新建一个二维n*n数组,不断往里填入数据。

5.2 代码

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        //先建立一个二维数组
        vector<vector<int>> result(n, vector<int>(n, 0));
        int startx = 0, starty = 0;
        int offset = 1; //因为每转一圈都需要,长度都会变短2
        int loop = n/2; //转的圈数
        int mid = n/2; //如果n为奇数,则需要往中间填一个数
        int count = 1; //需要往数组中填入的数字
        
        //使用左闭右开的原则
        while(loop--){
            int x = startx;
            int y = starty;

            for( ; y < starty + n - offset; y++){
                result[x][y] = count++;
            }
            for( ; x < startx + n - offset; x++){
                result[x][y] = count++;
            }
            for(; y > starty; y--){
                result[x][y] = count++;
            }
            for(; x > startx; x--){
                result[x][y] = count++;
            }

            startx++;
            starty++;
            offset += 2;
        }
        if(n%2){
            result[mid][mid] = count;
        }
        return result;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值