leetcode-数组中两元素的最大乘积

题目描述

给你一个整数数组 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

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/maximum-product-of-two-elements-in-an-array

题目分析

从描述中可以得出以下几个解题关键信息:

  1. 同一个数组,但下标不同的两个数
  2. 从所有结果中取最大值,即nums[i]和nums[j]是数组中最大的两个数

解题思路

暴力解法

能否简单的使用双重循环暴力破解呢?不能,因为暴力破解会存在下标i=j的情况,假设nums[i]是数组中最大的值,那么就nums[i]=nums[j],这两个数相乘就成了最大的结果了。所以不能简单的使用双重循环。

优化后的暴力解法

题目的关键信息是i和j不同,那么在双重循环中去除掉i=j的情况不就行了?
举个栗子,i和j循环的所有值是i=1,2,3....;j=1,2,3....;进行双重循环的时候i=1,j从1开始到nums.length-1,将i=j的情况去掉就是在初始化时让j=i+1。同理当i=2时,j也不能小于2,因为当i=1的时候已经计算了[1,2]的结果。所以为了降低时间复杂度,不能再计算[2,1]的结果了。所以j>i即j=i+1。代码如下:

public int maxProduct(int[] nums) {
    //时间复杂度O(n^2)   时间换空间
    int max = 0;
    for(int i=0;i<nums.length;i++) {
        for(int j = i+1;j<nums.length;j++) {
            max = Math.max((nums[i]-1)*(nums[j]-1), max);
        }
    }

    return max;
}

排序解法

既然是要取数组中两个不同的最大值,那么直接先进行排序然后取最前或者最后两个数不就行了?采用快速排序,平均时间复杂度为O(nlog2n)。代码就不列出了,网上很多实现。

空间换时间解法

能不能只进行一次遍历就解决呢?可以。
既然要保证取到最大的两个数,那么是不是可以给两个变量n1、n2,每次从nums数组中取一个数值替换n1、n2中更小的那个呢?这样nums数组只需要一次遍历,n1、n2也一直保证是当前遍历到的nums数组中最大的两个数。代码如下:

public int maxProduct(int[] nums) {
    //时间复杂度O(n),每次都将两个数里面最小的替换掉  空间换时间
    int n1=0,n2=0;
    for(int i=0;i<nums.length;i++) {
        if(n1<=n2) {
            n1=Math.max(nums[i], n1);
        } else {
            n2=Math.max(nums[i], n2);
        }
    }
    
    return (n1-1)*(n2-1);
}

总结

思维扩展

从这一道题想到了另外一题,如:给定一个数组,从中随机取3个数,共有多少种取法。
就是一个排列组合的问题,其实也是要去除重复的组合,可以采用暴力解法的优化方式去解,只是循环变成了三重。

posted @ 2022-08-26 10:23  竹堑  阅读(106)  评论(0编辑  收藏  举报