【水滴计划 | 每日两题】:删除有序数组中的重复项、长度最小的子数组

109 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第14天,点击查看活动详情

1、写在前面

大家好,我是翼同学,这里是【水滴计划 | 刷题日志】

每日两题,拒绝摆烂。

2、内容

2.1、题目一:删除有序数组中的重复项

链接:26. 删除有序数组中的重复项 - 力扣(LeetCode)

(1) 描述

image.png

image.png

(2) 举例

image.png

image.png

image.png

(3) 解题

用双指针解题即可。

代码如下:

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        // 1. 定义两个指针,分别指向数组的第一个元素和第二个元素
        int left = 0;
        int right = 1; 
        // 2. 遍历数组,将不重复的元素移到数组的左侧
        while(right < nums.size()) {
            if(nums[left] != nums[right]) {
                nums[left+1] = nums[right];
                left++;
            }
            right++;
        }
        // 3. 最后放回数组长度
        return left+1;
    }
};

image.png

这个解题思路其实很容易理解,可以看作去吃自助餐,数组中每个编号都代表一种食品,有个吃货决定,必须将每道菜都吃一遍,此时如果遇到没见过的编号,就将其拉到左边,按顺序排好,如果遇到见过的编号,则直接忽略。

举个例子:

  • 比如数组中元素为:0, 1, 1, 6, 9, 9
  • 此时保持第一个数字不要动,然后往后面看,数字是1,没见过,于是将1排在0的后面,接着再往后看,数字是11已经见过了,就直接忽略不管,再往后看,看到新面孔6,就将其拉到左边,排在0, 1的后面,以此类推。
  • 最后结果为0, 1, 6, 9

2.2、题目二:长度最小的子数组

链接:209. 长度最小的子数组 - 力扣(LeetCode)

(1) 描述

image.png

(2) 举例

image.png

image.png

image.png

image.png

(3) 解题

首先,暴力解法来一遍。

image.png

很可惜,执行结果超出时间限制。

为了降低时间复杂度,我们利用一个for循环来替代两个for循环的遍历操作,也就是双指针解法。这里的子数组更新操作也可以看成滑动窗口解法。

代码如下:

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        // 1. 存放运算结果
        int result = INT32_MAX; 
        // 2. 子数组元素之和
        int sum = 0;
        // 3. 子数组的长度
        int subL = 0;       
        // 4. 子数组起始位置
        int i = 0;
        // 5. 遍历数组,j指向子数组的终止位置
        for (int j = 0; j < nums.size(); j++) {
            // 5.1 计算当前子数组元素之和
            sum += nums[j];
            // 5.2 动态更新子数组起始位置i
            while (sum >= s) {
                // 取到当前子数组的长度
                subL = (j - i + 1);
                // 通过比较,判断当前子数组是否符合条件
                if(result >= subL) {
                    result = subL;
                }
                // 更新当前子数组的元素之和
                sum -= nums[i]; 
                // 更新子数组的起始位置i
                i++;
            }
        }
        // 6. 返回答案
        if(result == INT32_MAX) {
            // 说明result没有被赋值过,意味着没有符合条件的子数组
            return 0; 
        }else {
            // 返回运算结果
            return result;
        }
    }
};

image.png


  • 提问:为什么时间复杂度是O(n)O(n) ?
  • 记录:时间复杂度取决于每个元素被操作的次数,不是说for循环中加上while循环就会导致时间复杂度为O(n2)O(n^2),每个元素其实在滑动窗口后进来被操作一次,出去又被操作一次,因此时间复杂度为O(2×n)O(2×n),即O(n)O(n)

3、写在最后

好了,今天就刷到这里,明天再来。