力扣刷题 | 复习篇1:数组专题

之前停了太久没刷题,前面的都忘了,重新复习一下

704 二分查找

思路:首先这是一个查找问题,接着要发现题目给出的是有序数组(升序),且数组元素无重复(可用二分法),当满足以上条件时,就应该考虑是否用二分法

想到二分法,就要想到边界问题,这是二分法中最重要的问题,是左闭右开,还是左闭右闭,还是左开右闭?

选定一个边界,就可以开始写代码了!

本次选择的是左闭右闭区间,代码如下:

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0, 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 移除元素(双指针)

思路:这道题目要移除数组中的指定元素。需要注意的是,数组元素不可删除,只可覆盖,故这里的移除使用的其实是覆盖的操作。

由于暴力解法需要双层for循环,时间复杂度为O( n 2 n^2 n2),故考虑双指针,时间复杂度为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];
            }
            //如果当前元素等于val,则直接跳过,fast++
            //运行结束之后,slow指向当前数组下标的下一位,即为新数组长度
        }
        return slowIndex;
    }
};

977 有序数组的平方

问题:这题在写的过程中少了(nums.size(), 0)这一部分,就是缺少了对动态数组result的初始化,导致运行出错。因为我对c++的stl相关内容不了解,所以也不知道如何对vector(vector是C++标准模板库(STL)中的一个容器,它是一个动态数组,可以根据需要自动调整大小)进行初始化。

vector<int> result(nums.size(), 0);

这行代码的意思是设置result向量的长度为nums.size(),且初始化数组元素为0。

思路:方法说是双指针,但我感觉是三指针。因为要将平方之后的数据大小进行排序,又考虑到原有数据就是有排序过的,所以只要考虑负数平方之后变大的情况就可以了。因此,最大值只会出现在数组两端,故考虑头尾各放置一个指针来进行平方后的大小比较,再引入第三个指针来指向新数组的末端,从后往前填入数据(即从大到小)。

代码:

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[i] * nums[i];
                i++;
            }
            else {
                result[k--] = nums[j] * nums[j];
                j--;
            }
        }
        return result;
    }
};

209 长度最小的子数组

思路:在给定数组中找到连续子数组之和大于等于目标值的最短数组,并返回其长度。要注意是连续子数组。可以很自然的想到滑动窗口法(实现还是双指针),就是一个框框住数组,不断往前滑动,问题是怎么滑动,窗口长度怎么变?

要有一个for循环遍历数组,哪个指针来遍历?应该是后一个指针

代码:

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

59 螺旋矩阵 II

思路:本质是通过多个循环来完成每一条边的绘制,一个循环画一条边。需要注意的是,这里仍然存在边界问题,每一条边的起始点从哪里开始,到哪里结束,要搞清楚。根据对称原则,应该采用左闭右开区间,才能使得绘制的每一条边都等长。需要设置较多变量,写代码时不一定能写得出来。

这里又出现了和上面同样的问题,向量的初始化,这里算是二维向量,也即矩阵,初始化格式为

vector<vector<int>> res(n,vector<int>(n,0));

表示初始化了n个n维向量vector<int>(n),每个向量的初值为0。

代码:

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 offset = 1;
        int count = 1;
        while(loop) {
            int 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++;
            }
            loop--;
            startX++;
            startY++;
            offset++;
        }
        if(n % 2 == 1) {
            res[startX][startY] = count;
        }
        return res;
    }
};

数组专题小结

704 二分查找: 有序数组、无重复;重点考虑边界:左闭右开?左闭右闭?

27 移除元素: 数组不可删除,只可覆盖;双指针法,快指针遍历寻找新数组元素,慢指针将元素写进新数组

977 有序数组的平方: 有序数组平方后排序,考虑负数,最大值只会出现在两边,用双指针指向两端进行比较,将大的值填入新数组,新数组从后往前填充

209 长度最小的子数组: 寻找子数组之和达到目标值的连续的最短子数组,注意是连续,所以考虑滑动窗口法,本质是双指针;重点是后一个指针来遍历,前一个指针只有当子数组之和达到目标值之后,才会往后移动

59 螺旋矩阵 II: 没有什么技巧,就是通过多个for循环画出每一条边,要注意的仍然是边界问题,应采用左闭右开

小结: 二分查找和螺旋矩阵都要考虑边界问题;移除元素、有序数组的平方和长度最小的子数组都用到了双指针;说明数组专题中重点考虑边界双指针法

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值