【小航的算法日记】 线性枚举(一) - 最值算法

一、概念

二、模板

求n个数m个最大值(不严格):

 public int thirdMax(int[] nums) {
        int a = Integer.MIN_VALUE, b = Integer.MIN_VALUE, c = Integer.MIN_VALUE; // ...
        for(int num : nums) {
            if(num > a) {
                c = b; b = a; a = num;  // 注意先后赋值顺序
            }else if(num <= a && num > b) {
                c = b; b = num;
            }else if(num <= b && num > c) {
                c = num;
            }
        }
        return c == Integer.MIN_VALUE ? a : c;
    }

求n个数m个最大值(严格):

 public int thirdMax(int[] nums) {
        int a = Integer.MIN_VALUE, b = Integer.MIN_VALUE, c = Integer.MIN_VALUE; // ...
        for(int num : nums) {
            if(num > a) {
                c = b; b = a; a = num;  // 注意先后赋值顺序
            }else if(num < a && num > b) {
                c = b; b = num;
            }else if(num < b && num > c) {
                c = num;
            }
        }
        return c == Integer.MIN_VALUE ? a : c;
    }

三、例题

题:485. 最大连续 1 的个数

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

示例 1:

输入:nums = [1,1,0,1,1,1]
输出:3
解释:开头的两位和最后的三位都是连续 1 ,所以最大连续 1 的个数是 3.

示例 2:

输入:nums = [1,0,1,1,0,1]
输出:2

提示:

1 <= nums.length <= 105
nums[i] 不是 0 就是 1.

解:

解题思路:枚举

AC代码:

class Solution {
    public int findMaxConsecutiveOnes(int[] nums) {
        int maxCount = 0, count = 0;
        for(int num : nums) {
            if(num == 1) {
                count ++;
            }else {
                maxCount = Math.max(maxCount, count);
                count = 0;
            }
        }
        return Math.max(maxCount, count);
    }
}

题:1464. 数组中两元素的最大乘积

给你一个整数数组 nums,请你选择数组的两个不同下标 ij,使 (nums[i]-1)*(nums[j]-1) 取得最大值。

请你计算并返回该式的最大值。

示例 1:

输入:nums = [3,4,5,2]
输出:12 
解释:如果选择下标 i=1 和 j=2(下标从 0 开始),则可以获得最大值,(nums[1]-1)*(nums[2]-1) = (4-1)*(5-1) = 3*4 = 12 。 

示例 2:

输入:nums = [1,5,4,5]
输出:16
解释:选择下标 i=1 和 j=3(下标从 0 开始),则可以获得最大值 (5-1)*(5-1) = 16 。

示例 3:

输入:nums = [3,7]
输出:12

提示:

2 <= nums.length <= 500
1 <= nums[i] <= 10^3

解:

解题思路:枚举

AC代码:

class Solution {
    public int maxProduct(int[] nums) {
        return (getMax(nums) - 1) * (getMax(nums) - 1);
    }
    public int getMax(int[] nums) {
        int max = 0;
        int p = -1;
        for(int i = 0; i < nums.length; i ++) {
            if(max < nums[i]){
               max = nums[i]; 
               p = i;
            } 
        }
        nums[p] = 0;
        return max;
    }

}

题:153. 寻找旋转排序数组中的最小值

已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:
若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]
注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。

给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。

示例 1:

输入:nums = [3,4,5,1,2]
输出:1
解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。

示例 2:

输入:nums = [4,5,6,7,0,1,2]
输出:0
解释:原数组为 [0,1,2,4,5,6,7] ,旋转 4 次得到输入数组。

示例 3:

输入:nums = [11,13,15,17]
输出:11
解释:原数组为 [11,13,15,17] ,旋转 4 次得到输入数组。

提示:

n == nums.length
1 <= n <= 5000
-5000 <= nums[i] <= 5000
nums 中的所有整数 互不相同
nums 原来是一个升序排序的数组,并进行了 1 至 n 次旋转

解:

解题思路:二分

AC代码:

class Solution {
    public int findMin(int[] nums) {
        int l = 0, r = nums.length - 1;
        if(nums[r] > nums[l]) return nums[0];
        while(l < r) {
            int mid = (l + r)/ 2;
            if(nums[mid] < nums[r]) r = mid;
            else l = mid + 1;
        }
        return nums[l];
    }
}

题:154. 寻找旋转排序数组中的最小值 II

已知一个长度为n的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,4,4,5,6,7] 在变化后可能得到:

  • 若旋转 4 次,则可以得到 [4,5,6,7,0,1,4]
  • 若旋转 7 次,则可以得到 [0,1,4,4,5,6,7]

注意,数组 [a[0], a[1], a[2], ..., a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]]

给你一个可能存在 重复 元素值的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。

示例 1:

输入:nums = [1,3,5]
输出:1

示例 2:

输入:nums = [2,2,2,0,1]
输出:0

提示:

n == nums.length
1 <= n <= 5000
-5000 <= nums[i] <= 5000
nums 原来是一个升序排序的数组,并进行了 1 至 n 次旋转

进阶:

这道题是 寻找旋转排序数组中的最小值 的延伸题目。
允许重复会影响算法的时间复杂度吗?会如何影响,为什么?

解:

解题思路:二分法

AC代码:

class Solution {
    public int findMin(int[] nums) {
        int l = 0, r = nums.length - 1;
        while(l < r) {
            int mid = (l + r) / 2;
            if(nums[mid] > nums[r]) l = mid + 1; // mid不可能是答案
            else if(nums[mid] < nums[r]) r = mid; // mid可能是答案
            else r --;
        }
        return nums[l];
    }
}

题:414. 第三大的数

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

示例 1:

输入:[3, 2, 1]
输出:1
解释:第三大的数是 1 。

示例 2:

输入:[1, 2]
输出:2
解释:第三大的数不存在, 所以返回最大的数 2 。

示例 3:

输入:[2, 2, 3, 1]
输出:1
解释:注意,要求返回第三大的数,是指在所有不同数字中排第三大的数。
此例中存在两个值为 2 的数,它们都排第二。在所有不同数字中排第三大的数为 1 。

提示:

1 <= nums.length <= 104
-231 <= nums[i] <= 231 - 1
  • 进阶:你能设计一个时间复杂度 O(n) 的解决方案吗?

解:

解题思路:枚举

AC代码:

class Solution {
    public int thirdMax(int[] nums) {
        long a = Long.MIN_VALUE, b = Long.MIN_VALUE, c = Long.MIN_VALUE; // 注意取值范围 
        for(long num : nums) {
            if(num > a) {
                c = b; b = a; a = num;  // 注意先后赋值顺序
            }else if(num < a && num > b) {
                c = b; b = num;
            }else if(num < b && num > c) {
                c = num;
            }
        }
        return c == Long.MIN_VALUE ? (int)a : (int)c;
    }
}

题:628. 三个数的最大乘积

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

示例 1:

输入:nums = [1,2,3]
输出:6

示例 2:

输入:nums = [1,2,3,4]
输出:24

示例 3:

输入:nums = [-1,-2,-3]
输出:-6

提示:

3 <= nums.length <= 104
-1000 <= nums[i] <= 1000

解:

解题思路:

分三种情况:

  1. 全为正数:res = max1 * max2 * max3
  2. 全为负数:res = max1* max2* max3
  3. 有正有负:res = max(max1 * max2 * max3(两正一负), min1 * min2 * max1(两负一正))

值得注意的是:这里的最大最小不严格,可以相等。

AC代码:

class Solution {
    public int maximumProduct(int[] nums) {
        int max1 = Integer.MIN_VALUE, max2 = Integer.MIN_VALUE, max3 = Integer.MIN_VALUE;
        int min1 = Integer.MAX_VALUE, min2 = Integer.MAX_VALUE;
        for(int num : nums) {
            // 寻找前三个max(不严格,相等也算)
            if(num > max1) {
                max3 = max2; max2 = max1; max1 = num;
            }else if(num <= max1 && num > max2) {
                max3 = max2; max2 = num;
            }else if(num <= max2 && num > max3){
                max3 = num;
            }
            // 寻找后两个min(不严格,相等也算)
            if(num < min1) {
                min2 = min1; min1 = num;
            }else if(num < min2 && num >= min1) {
                min2 = num;
            }
        }
        return Math.max(max1 * max2 * max3, min1 * min2 * max1);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值