zoukankan      html  css  js  c++  java
  • LeetCode算法题-Maximum Product of Three Numbers(Java实现)

    这是悦乐书的第275次更新,第291篇原创

    01 看题和准备

    今天介绍的是LeetCode算法题中Easy级别的第143题(顺位题号是628)。给定一个整数数组,从其中找出三个数,使得乘积最大。例如:

    输入:[1,2,3]

    输出:6

    输入:[1,2,3,4]

    输出:24

    注意

    • 数组的长度范围为[3,10^4],元素值范围为[-1000,1000]。

    • 任意三个数字的乘积不会超过32位有符号整数的范围。

    本次解题使用的开发工具是eclipse,jdk使用的版本是1.8,环境是win7 64位系统,使用Java语言编写和测试。

    02 第一种解法

    要想三个数的乘积最大化,那么他们的值在数组中肯定是最大的,所以我们需要排序。

    元素的取值范围是[-1000,1000],会存在负数的值大于正数的值的情况。对数组排序后,第三个数肯定是数组最后一个元素,如果数组中存在负数,前两个负数的乘积大于倒数第二个元素与倒数第三个元素的乘积,那么第一个数与第二个数就是数组的前两位元素,反之就是数组的倒数第二个元素与倒数第三个元素,我们从这两种情况中取最大值即可。

    此解法时间复杂度是O(nlog(n)),空间复杂度是O(1)。

    public int maximumProduct(int[] nums) {
        if (nums == null || nums.length < 3) {
            return 0;
        }
        // 排序
        Arrays.sort(nums);
        // 取两种情况的较大者
        return Math.max(nums[0]*nums[1]*nums[nums.length-1], nums[nums.length-1]*nums[nums.length-2]*nums[nums.length-3]);
    }
    

    03 第二种解法

    对第一种解法中借助Arrays.sort方法来实现排序,我们可以再优化下,让排序时间复杂度降到O(n),使用记数排序算法来实现。记数排序算法在之前的一道题目里用过,可以稍后去看看文末的链接。

    此解法的时间复杂度是O(n),空间复杂度是O(n),使用了新数组,n为新数组的长度。

    public int maximumProduct2(int[] nums) {
        if (nums == null || nums.length < 3) {
            return 0;
        }
        // nums的取值范围是[-1000,1000],定义一个新数组的长度比它多一个即可
        int[] temp = new int[2001];
        for (int n : nums) {
            // 以nums的元素值加1000作为新数组的索引,出现次数作为值
            temp[n+1000]++;
        }
        int index = 0;
        for (int i=0; i<temp.length; i++) {
            // 遇到了nums的元素
            if (temp[i] != 0) {
                // 可能出现多次,temp[i]为nums中该元素出现的次数
                for (int j=0; j<temp[i]; j++) {
                    nums[index++] = i-1000;
                }
            }
        }
        // 依旧取两者中较大的那个
        return Math.max(nums[0]*nums[1]*nums[nums.length-1], nums[nums.length-1]*nums[nums.length-2]*nums[nums.length-3]);
    }
    

    04 第三种解法

    是不是必须要排序才能找到乘积最大的三个元素?

    我们可以换个场景,找一组数据中的最大值或者最小值,最简单的做法是直接遍历,依次比较就行,此题我们是不是也可以使用同样的思路?只不过原来是找一个最大值或最小值,现在变成要找三个最大值以及两个最小值了。

    此解法的时间复杂度是O(n),空间复杂度是O(1)。

    public int maximumProduct3(int[] nums) {
        if (nums == null || nums.length < 3) {
            return 0;
        }
        // 定义前三个最大值变量
        int max1 = Integer.MIN_VALUE;
        int max2 = Integer.MIN_VALUE;
        int max3 = Integer.MIN_VALUE;
        // 定义前两个最小值变量
        int min1 = Integer.MAX_VALUE;
        int min2 = Integer.MAX_VALUE;
        for (int n : nums) {
            // 做比较并进行替换,从后往前
            if (n > max1) {
                max3 = max2;
                max2 = max1;
                max1 = n;
            } else if (n > max2) {
                max3 = max2;
                max2 = n;
            } else if (n > max3) {
                max3 = n;
            }
            if (n < min1) {
                min2 = min1;
                min1 = n;
            } else if (n < min2) {
                min2 = n;
            }
        }
        // 同样是取两者之间的较大者
        return Math.max(max1*max2*max3, min1*min2*max1);
    }
    

    05 小结

    此题本质上是找数组中的最大值或最小值,无论是找单个还是多个,无论是使用排序算法还是其他方式,核心思路都不变。至于上面第二种解法中的记数排序算法,有个使用前提,就是得知道数组元素的取值范围,如果题目有给取值范围是最好的,没给的话,就需要自己去取了。

    算法专题目前已日更超过四个月,算法题文章143+篇,公众号对话框回复【数据结构与算法】、【算法】、【数据结构】中的任一关键词,获取系列文章合集。

    以上就是全部内容,如果大家有什么好的解法思路、建议或者其他问题,可以下方留言交流,好看、留言、转发就是对我最大的回报和支持!

  • 相关阅读:
    js的同步与异步
    单体应用SSM
    Spring 事务管理简介
    Linux
    Docker
    spring Cloud Netflix
    平台即服务
    MySQL InnoDB 索引组织表 & 主键作用
    Innodb Double Write
    Laravel 5.6: Specified key was too long error
  • 原文地址:https://www.cnblogs.com/xiaochuan94/p/10520806.html
Copyright © 2011-2022 走看看