力扣刷题攻略数组篇-数组的遍历


文章内容是自己刷leetcode官方刷题攻略的一些经验与总结。
题目链接详见 leetcode刷题攻略
如果喜欢的话,别忘了点个赞哦 ^ _ ^

一.485.最大连续1的个数

1.题目描述

题目链接

在这里插入图片描述

2.题目分析与解答

因为数组中只有0和1两个元素,所以我们可以维护一个count用来记录当前连续1的个数,用maxCount记录最大连续1的个数

当遇到1,把count++,当遇到0,更新maxCount,重置count。
考虑到结尾数字可能是1,会导致maxCount没有更新,所以遍历完数组后再次更新maxCount

C++代码如下:

class Solution {
public:
    int findMaxConsecutiveOnes(vector<int>& nums) {
        int cnt = 0;
        int maxCnt = 0;
        for(int i = 0; i < nums.size(); i ++) {
            if(nums[i] == 1) {
                cnt ++;
            } else {
                maxCnt = max(maxCnt, cnt);
                cnt = 0;
            }
        }

        //最后一个元素可能是1
        maxCnt = max(maxCnt, cnt);

        return maxCnt;
    }
};

二.495.提莫攻击

1.题目描述

题目链接

在这里插入图片描述

2.题目分析与解答

这个题目的关键点是每次攻击会重置中毒时间

我们最终要记录的是总中毒时间,那么在遍历数组过程中,有这么两种情况:一是两次攻击间隔小于单次中毒时间,那么中毒时间会刷新,我们需要将答案加上攻击间隔的时间;二是两次攻击间隔大于单次中毒时间,那么需要将答案加上单次中毒时间

所以最终答案更新方法就是每次加上 min(攻击时间间隔,单次中毒时间)

考虑到最后一次攻击没有处理,最终的答案应该再加上一个单次中毒时间。

C++代码如下:

class Solution {
public:
    int findPoisonedDuration(vector<int>& timeSeries, int duration) {
        int ans = 0;
        for(int i = 1; i < timeSeries.size(); i ++) {
            int x = timeSeries[i] - timeSeries[i - 1];
            ans += min(x, duration);
        }

        return ans + duration;
    }
};

三.414.第三大的数

1.题目描述

题目链接

在这里插入图片描述

2.题目分析与解答

这个题目如果不考虑时间复杂度的话,可以直接 sort 排序后找第三大的数,时间复杂度是 O(nlogn)。
但是你可以用 O(n) 的时间复杂度解决这个问题吗?

如果要求时间复杂度是 O(n) 就不能使用排序算法了,可以这么思考:
我们可以在遍历数组过程中保留前三个大的元素,那么怎么保留呢?可以使用有序集合这个数据结构。

我们在遍历数组过程中,将每个元素插入到集合中,如果集合的元素个数大于三,说明我们保留的元素过多,需要删除当前集合中最小的元素,因为是有序集合,所以把集合头部的元素(就是四个元素中的最小元素)删掉就可以。

因为原始数组的元素个数可能小于三个,我们最后输出的时候需要判断一下:如果元素没有三个,输出结果为最大元素(集合的末尾),否则输出结果为第三大元素(集合的头部)。

C++代码如下:

class Solution {
public:
    int thirdMax(vector<int>& nums) {
        //使用有序集合
        set<int> s;
        for(int i = 0; i < nums.size(); i ++) {
            s.insert(nums[i]);
            if(s.size() > 3) {
                s.erase(s.begin()); //擦去小的
            }
        }

        return s.size() == 3 ? *s.begin() : *s.rbegin();

        // c.begin() 返回一个迭代器,它指向容器c的第一个元素

        // c.end() 返回一个迭代器,它指向容器c的最后一个元素的下一个位置

        // c.rbegin() 返回一个逆序迭代器,它指向容器c的最后一个元素

        // c.rend() 返回一个逆序迭代器,它指向容器c的第一个元素前面的位置


    }
};

四.628三个数的最大乘积

1.题目描述

题目链接

在这里插入图片描述

2.题目分析与解答

如果数组中只有正数或者只有负数,那么这道题就没有什么难度了,但是现在数组中正负数都可能有,那么就需要分情况讨论。

我们可以先将数组排个序,方便讨论,有以下几种情况:

  • 如果数组中只有正数,那么我们选取最大的三个正数就可以;
  • 如果数组中只有负数,那最终结果还是负数,我们需要使这个负数最大,也就是使其绝对值最小,那么我们选取最大的三个负数就可以;
  • 如果数组中有正数也有负数,那么结果可能是三个最大正数的乘积,也可能是两个最小负数(绝对值最大)与一个最大正数的乘积,也有可能是一个负数与两个正数的乘积(这种情况下数组中只会有三个数)。

那么综合上面的几种情况,其实只涉及了数组中的这么两个组合:一个组合是数组中的最大的三个元素的乘积,一个组合是数组中最大的一个元素与最小的两个元素的乘积。

C++代码如下:

class Solution {
public:
    int maximumProduct(vector<int>& nums) {
        //排序
        //如果全为正数:结果是最大的三个正数(最后三个数)
        //如果全为负数:结果是最大的三个负数(最后三个数)
        //如果有正数有负数
        //  如果结果只有正数(最后三个数)
        //  如果结果为一个正数+两个负数(最大一个数和最小两个数)
        //	如果结果为两个正数+一个负数(最后三个数)

        //其实总的就是找最大的三个数和最小的两个数,不用排序也可以

        sort(nums.begin(), nums.end());
        int n = nums.size();
        return max(nums[n - 1] * nums[n - 2] * nums[n - 3], nums[n - 1] * nums[0] * nums[1]);
    }
};

下面是不使用排序,时间复杂度为 O(n) 的方法。
我在上文代码的注释中也提到了,我们只用找数组中最大的三个数和最小的两个数就可以,用 max1,max2,max3,min1,min2 来记录这些元素即可,在遍历数组过程中更新。

C++代码如下:

class Solution {
public:
    int maximumProduct(vector<int>& nums) {
        //排序
        //如果全为正数:结果是最大的三个正数(最后三个数)
        //如果全为负数:结果是最大的三个负数(最后三个数)
        //如果有正数有负数
        //  如果结果只有正数(最后三个数)
        //  如果结果为一个正数+两个负数(最大一个数和最小两个数)
        //	如果结果为两个正数+一个负数(最后三个数)

        //其实总的就是找最大的三个数和最小的两个数,不用排序也可以
		//max1表示最大的数,min1表示最小的数
        int max1 = INT_MIN, max2 = INT_MIN, max3 = INT_MIN;
        int min1 = INT_MAX, min2 = INT_MAX;

        for(int x : nums) {
            if(x < min1) {
                min2 = min1;
                min1 = x;
            } else if(x < min2) {
                min2 = x;
            }

            if(x > max1) {
                max3 = max2;
                max2 = max1;
                max1 = x;
            } else if(x > max2) {
                max3 = max2;
                max2 = x;
            } else if(x > max3) {
                max3 = x;
            }
        }

        return max(max1 * max2 * max3, min1 * min2 * max1);
    }
};
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Echo夏末

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值