Leetcode刷题---线性枚举之最值算法

本文是(第17讲) 线性枚举(一) - 最值算法中所涉及课后习题的解答,发帖来记录自己关于这些题的理解和做题过程中思路,如果有错误,欢迎批评指正。

1.最大连续1的个数

题目:给定一个二进制数组, 计算其中最大连续 1 的个数。

主要思路:
遍历数组中的每个数,若为1则计数加一,若为0,更新最大连续的1的个数并将其存入ans中,然后将计数清空,继续遍历,由于出现0才会更新ans,若最大连续1的串出现在数组尾部,由于其后无0,不会将该部分连续1的个数更新入ans,所以最后需在循环完成后再次更新ans。

代码:

class Solution {
public:
    int findMaxConsecutiveOnes(vector<int>& nums) {
        int ans=0,temp=0;
        for(auto num:nums){
            if(num==1){
                temp++;
            }
            else{
                ans=max(ans,temp);
                temp=0;
            }
        }
        ans=max(ans,temp);
        return ans;
    }
};

2.数组中两元素的最大乘积

题目:给你一个整数数组 nums,请你选择数组的两个不同下标的数,使得对其分别减一后的两个数的乘积取得最大值。请你计算并返回该最大值。

代码:

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        return (nums[nums.size()-1]-1)*(nums[nums.size()-2]-1);
    }
};

3.寻找旋转数组中的最小值

题目:已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] ,旋转 4 次后可得到 [4,5,6,7,0,1,2]。给你一个元素值互不相同的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的最小元素 。

主要思路:
对于这个题,完全可以使用排序加取最小值的方法,但是这样的话就没有用到旋转数组这一特性。

对于旋转数组,由于其初始状态为升序,所以它只可能有三种状态:

(1) 最小值在0位置,即升序数组;

(2) 最小值在s-1位置,即降序数组;

(3) 最小值在中间,即前降后升数组;

可以看出,它总是部分有序的,所以可以使用二分查找的方法,将下标0,s-1初始化为左右端点(s为数组长度),然后计算中点,若中点处的值大于右端点,此时说明最小值在中点和右端点之间,所以令中点加一变为了新的左端点(因为中点处的值绝对不会是最小值,起码它比右端点的值要大);若中点处的值小于右端点,那么最小值在左端点和中点之间,此时中点变为了新的右端点(因为中点处的值可能就是最小值),不断循环遍历,直至找到最小值,最小值即为最终右端点的值。

代码:

//排序+取最小值
class Solution {
public:
    int maxProduct(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        return nums[0];
    }
};
//二分查找
class Solution {
public:
    int findMin(vector<int>& nums) {
        int left=0,right=nums.size()-1;
        while(left<right){
            int mid=left+(right-left)/2;
            if(nums[mid]>nums[right]){
                left=mid+1;
            }else if(nums[mid]<nums[right]){
                right=mid;
            }
        }
        return nums[right];
    }
};

4.寻找旋转数组中的最小值II

题目:已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,4,4,5,6,7] 在旋转 4 次后可得到 [4,5,6,7,0,1,4]。给你一个可能存在重复元素值的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。

主要思路:
该题与前面一题唯一的区别就是数组中存在重复元素,这样的话在二分的时候就有额外的一种情况,即中点和右端点处的值一样,但最小值在这两点之间,例如:[3,3,3,3,3,1,1,3,3,3] 这样的数组,此时若直接忽视有部分,会导致最小值丢失,所以需要将右端点小心地回一步步回退,这样的话,它一定能退到最小值“坑”中。

代码:

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

5.第三大的数

题目:给你一个非空数组,返回此数组中第三大的数 。如果不存在,则返回数组中最大的数。

主要思路:
(1) 排序+遍历,若找到第三大的数,将其返回,否则返回最大值。

(2) 使用有序集合,始终保持它的大小不超过三,此时,该集合中所存的数为数组的最大、次大、第三大值,最后若集合大小为三,就返回集合的首个元素,否则,返回集合尾部元素(集合中的元素大小顺序为升序)。

代码:

//排序+遍历
class Solution {
public:
    int thirdMax(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        int index=1;
        for(int i=nums.size()-1;i>0;i--){
            if(nums[i-1]!=nums[i]){
                index++;
                if(index==3){
                    return nums[i-1];
                }
            }
        }
        return nums[nums.size()-1];
    }
};
//有序集合
class Solution {
public:
    int thirdMax(vector<int>& nums) {
        set<int> chart;
        for(auto num:nums){
            chart.insert(num);
            if(chart.size()>3){
                chart.erase(chart.begin());
            }
        }
        return chart.size()==3? *chart.begin() : *chart.rbegin();
    }
};

6.三个数的最大乘积

题目:给你一个整型数组 nums ,在数组中找出由三个数组成的最大乘积,并输出这个乘积。

主要思路:
首先对数组排序,然后若数组全正或仅有一个负数,最大乘积值即为升序数组后三个数的乘积,若数组有两个以上负数,则最大乘积值即为升序数组前两个数和最后一个数的的乘积,综上,对于所有情况,答案为升序数组 “后三个数的乘积” 和 ”前两个数和最后一个数的的乘积“ 这两个结果中的最大值。既然如此,那么也可以不用排序,直接找出数组中最大的三个数以及最小的两个数,然后计算结果即可。

代码:

//排序
class Solution {
public:
    int maximumProduct(vector<int>& nums) {
        int n=nums.size();
        sort(nums.begin(),nums.end());
        return max(nums[0]*nums[1]*nums[n-1],nums[n-1]*nums[n-2]*nums[n-3]);
    }
};
//遍历
class Solution {
public:
    int maximumProduct(vector<int>& nums) {
        int n=nums.size();
        int max1=INT_MIN,max2=INT_MIN,max3=INT_MIN,min1=INT_MAX,min2=INT_MAX;
        for(auto num:nums){
            if(num<min1){
                min2=min1;
                min1=num;
            }else if(num<min2){
                min2=num;
            }
        }
        for(auto num:nums){
            if(num>max1){
                max3=max2;
                max2=max1;
                max1=num;
            }else if(num>max2){
                max3=max2;
                max2=num;
            }else if(num>max3){
                max3=num;
            }
        }
        return max(max1*max2*max3,min1*min2*max1);
    }
};
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值