跟我一起刷leetCode演算法題11之 Maximum Product of Three Numbers

weixin_33860722發表於2017-08-10

628. Maximum Product of Three Numbers

這是leetCode第628題

題目

Given an integer array, find three numbers whose product is maximum and output the maximum product.

意思是說:
給出一個整數陣列,找出三個數字,它們的乘積是最大的。輸出最大的乘積。

陣列中的整數可能為負數。

我的思路

三個整數相乘,其中必有兩個數相乘是非負數。
所以,將陣列排序後,兩個數相乘的最大非負數就在陣列的兩端(絕對值最大的數,在陣列兩端)。
如下面這個陣列:
[-99,-8,1,2,100,110] 兩個數相乘的最大非負數為100*110

[-99,-188,1,2,100,110] 兩個數相乘的最大非負數為-99*-188

[1,2,3,9,11] 兩個數相乘的最大非負數為9*11

[-9,2,3,8,12] 兩個數相乘的最大非負數為8*12

既然我們已經確定了兩個數最大的乘積,那麼只要我們確定第三個數,就把結果確定下來了。

假設:

把排序後的陣列稱為newArray,陣列長度L
如果newArray[0] * newArray[1]是最大的非負整數,那麼陣列中剩下的最大數字,就在陣列的最右邊。
可以從以下例子得出上述結論:

[-9,-8,1,2,3]  -9*-8*3最大
[-9,-8,-7,-7,-6,0] -9*-8*0 最大
[-9,-8,-7,-7,-6] -9*-8*-6 最大

如果newArray[L-1] * newArray[L-2]是最大的非負整數,那麼陣列中剩下的最大數字,就在陣列的L-3位置。

可以從以下例子得出上述結論:

[1,2,3,4,6,7]  7*6*4 最大
[-1,-2,3,4,6,7] 7*6*4最大
[-5,-4,-3,-1,6,7] 7*6*-1最大

程式碼如下

  /**
 * @param {number[]} nums
 * @return {number}
 */
var maximumProduct = function (nums) {
    var l = nums.length;
    nums.sort(function (a, b) {
        return a - b;
    });
    max1 = nums[0] * nums[1] * nums[l - 1];
    max2 = nums[l - 1] * nums[l - 2] * nums[l - 3];
    return Math.max(max1, max2);
 }

這是我的演算法,但是我利用了sort()方法,演算法的時間複雜度為O(nlogn)

下面介紹一下時間複雜度為O(n)的演算法。

 /**
 * @param {number[]} nums
 * @return {number}
 */
var maximumProduct = function (nums) {
    var min1=min2=Number.MAX_SAFE_INTEGER,     
    max1=max2=max3=Number.MIN_SAFE_INTEGER;
    var l = nums.length;
    var n = '';
    for (var i = 0; i < l; i++) {
        n = nums[i];
        if (n <= min1) {
            min2 = min1;
            min1 = n;
        } else if (n <= min2) {     
            min2 = n;
        }
        if (n >= max1) {          
            max3 = max2;
            max2 = max1;
            max1 = n;
        } else if (n >= max2) {     
            max3 = max2;
            max2 = n;
        } else if (n >= max3) { 
            max3 = n;
        }
    }
    return Math.max(min1 * min2 * max1, max1 * max2 * max3);
}

這個演算法的目的,就是找出陣列中的兩個最小的整數,和三個最大的整數。其實就是排序後的陣列中,最左側的兩個數和最右側的三個數。

下面比較下,兩種演算法的效率如何?

利用下面程式碼生成一個長度為10000000的陣列。

node product.js 

product.js 的程式碼如下:

var fs = require("fs");
var nums =[];
var boundary = 10000000;
for(var i=0;i<boundary;i++){
    var num = Math.round(Math.random()*boundary);
    num = num%2===0?num:-num;
    nums.push(num);
}
//轉成字串
var str = "var array=["+nums+"];module.exports=array;";
//寫入Array.js檔案,生成了js程式碼
fs.writeFile('Array.js', str,  function(err) {
   if (err) {
       return console.error(err);
   }
   console.log("資料寫入成功!");
});

執行我的演算法:

var start = new Date().getTime();
console.log("result:"+maximumProduct(nums));
var end = new Date().getTime();
console.log("time:"+(end-start));

結果如下:

 result:999999800000010000000
 time:4477

執行第二種演算法的結果如下:

result:999999800000010000000
time:91

很顯然,第二種演算法的速度更快。

相關文章