解决三个数组元素的最大积,无需排序

时间:2014-05-06 06:28:11

标签: java algorithm sorting

codility.com上的MaxProductOfThree任务有多种答案,其中大多数都涉及排序算法。

问题是:

给出了由N个整数组成的非空零索引数组A.

问题是找到给定数组中3个元素的最大乘积。

阵列的长度在3到100,000之间

数组A的每个元素都是[-1,000..1,000]

范围内的整数
    expected worst-case time complexity is O(N*log(N));

    expected worst-case space complexity is O(1), 

超出输入存储(不计入输入参数所需的存储空间)。 例如:

  a[0] = -3;
  a[1] = 7;
  a[2] = 2;
  a[3] = 1;
  a[4] = 5;
  a[5] = 7;

最大乘积是[1] * a [4] * a [5] = 245

除了涉及排序的O(n log n)方法之外,是否存在线性时间解决此问题的方法?

18 个答案:

答案 0 :(得分:11)

/*    The method get the max product of 3 consists in basically find the biggest 3 numbers from the array and the smallest 2 numbers from the array in just 1 iteration over the array. Here is the java code:*/

    int solution(int[] a) {
/* the minimums initialized with max int to avoid cases with extreme max in array and false minims 0 minimums returned */

        int min1 = Integer.MAX_VALUE;
        int min2 = Integer.MAX_VALUE;
/* the same logic for maximum initializations but of course inverted to avoid extreme minimum values in array and false 0 maximums */

        int max1 = Integer.MIN_VALUE;
        int max2 = Integer.MIN_VALUE;
        int max3 = Integer.MIN_VALUE;

//the iteration over the array

        for (int i = 0; i < a.length; i++) {

//test if max1 is smaller than current array value

            if (a[i] > max1) {
            //if a[i] is greater than the biggest max then a chain reaction is started,
            // max3 will be max2, max2 will be actual max1 and max1 will be a[i]    
                max3=max2;
                max2=max1;
                max1=a[i];
/* in case if current a[i] isn't bigger than max1 we test it to see maybe is bigger than second
 max. Then the same logic from above is applied for the max2 amd max3 */

            }else if(a[i]>max2){
                max3 = max2;
                max2 = a[i];
/* finally if current array value isn't bigger than max1 and max2 maybe is greater than max3 */

            }else if(a[i]>max3){
                max3 = a[i];
            }

/* The logic from above with maximums is is applied here with minimums but of course inverted to
discover the 2 minimums from current array. */

            if (a[i] < min1) {
                min2 =min1;
                min1=a[i];
            } else if (a[i] < min2) {
                min2 = a[i];
            }
        }
/* after we discovered the 3 greatest maximums and the 2 smallest minimums from the array
we do the 2 products of 3 from the greatest maximum and the 2 minimums . This is necessary
because mathematically the product of 2 negative values is a positive value, and because of
this the product of min1 * min2 * max1 can be greater than max1 * max2 * max3
 and the product built from the the 3 maximums. */

        int prod1 = min1 * min2 * max1;
        int prod2 = max1 * max2 * max3;

//here we just return the biggest product

        return prod1 > prod2 ? prod1 : prod2;

    } 

答案 1 :(得分:2)

有很多不错的答案,但是我认为这个答案有些优雅,100% on codility也很重要。


public static int solution(int[] A) {
    Arrays.sort(A);
    int F = 0, L = A.length - 1;
    int s1 = A[F] * A[F + 1] * A[F + 2];
    int s2 = A[F] * A[F + 1] * A[L];
    int s3 = A[F] * A[L - 1] * A[L];
    int s4 = A[L - 2] * A[L - 1] * A[L];
    return Math.max(Math.max(s1, s2), Math.max(s3, s4));
}

答案 2 :(得分:1)

这是一个O(n log n)解决方案。 首先我们对数组进行排序, 然后知道两个具有重要价值的负数会产生更大的正数,我们需要计算数组左边的最大值,以及数组右边的3个元素的乘积,并比较哪一个更大。

以下是示例代码:

// [1,2,3,4] = 24
  public int solution(int[] sortedArray) {
       Arrays.sort(sortedArray);
       int length = sortedArray.length;
       int  P, Q, R;
       int maximumLeft = Integer.MIN_VALUE, maximumRight = Integer.MIN_VALUE;

       P = sortedArray[length - 3];
       Q = sortedArray[length - 2];
       R = sortedArray[length - 1];
       maximumRight = P * Q * R;

       P = sortedArray[0];
       Q = sortedArray[1];
       R = sortedArray[length -1];

       maximumLeft = P * Q * R;


       return maximumRight > maximumLeft ? maximumRight : maximumLeft;
   }

不要忘记导入java.util.Arrays; 请参阅此链接以获取Java文件。

答案 3 :(得分:1)

Kotlin 没有排序。

我想知道为什么这里有这么多答案忽略了问题标题“不排序”!

    fun solution(A: IntArray): Int {
        // write your code in Kotlin
        if (A.size < 3) return -1

        var max1: Int = Int.MIN_VALUE
        var max2: Int = Int.MIN_VALUE
        var max3: Int = Int.MIN_VALUE
        var min1: Int = Int.MAX_VALUE
        var min2: Int = Int.MAX_VALUE

        A.forEach {
            when {
                it > max1 -> {
                    max3 = max2
                    max2 = max1
                    max1 = it
                }
                it > max2 -> {
                    max3 = max2
                    max2 = it
                }
                it > max3 -> {
                    max3 = it
                }
            }

            when {
                it < min1 -> {
                    min2 = min1
                    min1 = it
                }
                it < min2 -> {
                    min2 = it
                }
            }
        }

        return (min1 * min2 * max1).coerceAtLeast(max1 * max2 * max3)
    }

答案 4 :(得分:1)

  • 按升序对数组进行排序
  • Product1 = 已排序数组的最后 3 个数字的乘积
  • Product2 = 排序数组的最后一个数字和前两个数字的乘积
  • 返回最多两个以上产品
Javascript 中的

O(n) 解决方案可能是:

function solution(A) {
    let sorted = A.sort((a, b) => a-b);
    let max1 = A[A.length - 1] * A[A.length - 2] * A[A.length - 3];
    let max2 = A[0] * A[1] * A[A.length - 1];
    
    return Math.max(max1, max2);
}

答案 5 :(得分:1)

这可能有效:

int solution(vector<int>& A) {
    // write your code in C++14 (g++ 6.2.0)
    int missing = 1;
    vector<int> count(A.size());

    for (int n = 0; n < A.size(); n++) {
        if (A[n] > 0 && A[n] < (A.size() + 1)) {
            count[A[n] - 1]++;
        }
    }

    for (int n = 0; n < A.size(); n++) {
        if (count[n] == 0) {
            break;
        }

        missing++;
    }

    return missing;
}

答案 6 :(得分:1)

在排序数组中,最大乘积只有两个可能的选项。

1)最大(最后)三个元素

2)两个最小和最大元素的组合(在负元素的情况下,两个负元素的乘积为正,然后乘以数组的最大元素(如果为正,则可以产生最大乘积))

因此,解决方案是两者中的最大值,没有别的。下方的Codility为100/100。

// you can also use imports, for example:
// import java.util.*;

// you can write to stdout for debugging purposes, e.g.
// System.out.println("this is a debug message");
import java.util.Arrays;

class Solution {

    public int solution(int[] A) {

        int N = A.length;
        Arrays.sort(A);

        /**
         * When we sort an array there are two possible options for the largest product
         * 1) The largest (the last) three elements
         * 2) Combination of two smallest and the largest elements
         * Logic of (1): Obvious
         * Logic of (2): A pair of negatives multiplied returns a positive, which in combination with 
         * the largest positive element of the array can give the max outcome.
         * Therefore we return the max of options (1) and (2)
         */
        return Math.max(A[0] * A[1] * A[N - 1], A[N - 1] * A[N - 2] * A[N - 3]);
    }
}

欢呼

答案 7 :(得分:1)

在这里,你不会使用排序,仍然可以获得100%。

enter image description here

#include<limits>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int solution(vector<int> &A) {
    //Keep the absolute value for max 2 -ve num . As their mul will be +ve
    int abs1 = numeric_limits<int>::min();
    int abs2 = numeric_limits<int>::min();

    //Keep the max three num irrespective of sign
    int max1 = numeric_limits<int>::min();
    int max2 = numeric_limits<int>::min();
    int max3 = numeric_limits<int>::min();

    unsigned int size = A.size()-1;

    for (unsigned int i = 0; i <= size ; ++i) {
        if(A[i] > 0 ){

        } else if(abs(A[i]) >= abs1 ) {
            abs2 = abs1;
            abs1 = abs(A[i]);
        }else if(abs(A[i]) >= abs2 ) {
            abs2 = abs(A[i]);
        }

        if(A[i] >= max1 ){
            //Push max1s prev value to max2 and max2's prev val to max3
            max3 = max2;
            max2 = max1;
            max1 = A[i];
        } else if(A[i] >= max2 ) {
            max3 = max2;
            max2 = A[i];
        }else if(A[i] > max3 ) {
            max3 = A[i];
        }
    }
    // Either max 3 multiplication , or Max 2 negative num whose mul is +ve and the regular max
    return max(max1 * max2 * max3, abs1 * abs2 * max1);
}


int main(){
    vector<int> test = {-3, 1, 2, -2, 5, 6};
    cout << solution(test);
    return 0;
}

答案 8 :(得分:0)

这是我的解决方案,我只对所需的排序 https://app.codility.com/demo/results/training68T6KT-NY6/

public int solution(int[] A) {
    // write your code in Java SE 8
    int result;
    for (int i = 0; i < 3; i++) {
        for (int j = i; j < A.length; j++) {
            if (A[i] < A[j]) {
                int temp = A[i];
                A[i] = A[j];
                A[j] = temp;
            }
        }
    }

    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < A.length - i; j++) {
            if (A[A.length - 1 - i] > A[j]) {
                int temp = A[A.length - 1 - i];
                A[A.length - 1 - i] = A[j];
                A[j] = temp;
            }
        }

    }
    if ((A[A.length - 1] < 0) && A[A.length - 1] * A[A.length - 2] > 0) {

        result = A[0] * A[A.length - 1] * A[A.length - 2];
        if (result > A[0] * A[1] * A[2])
            return result;
    }
    return A[0] * A[1] * A[2];
}

答案 9 :(得分:0)

使用JavaScript(Node.js 8.9.4):

function solution(A) {
     // first we order it
     A.sort((a, b) => (a - b));

     // we see the first two possibilities and we compare them        
     let val1 = A[A.length - 1] * A[A.length - 2] * A[A.length - 3]

     let val2 = A[A.length - 1] * A[0] * A[1]

     // we return the higher value
     if (val1 > val2) { return val1 } else { return val2 }
}

答案 10 :(得分:0)

得分为100%的Python解决方案

import sys
def solution(A):
    if len(A) < 3:
         return 0
    min_value = sys.maxsize*-1
    max_value = sys.maxsize
    positive_nus = [min_value]*3
    negative_nus =[max_value]*2


    for i in range(0,len(A)):
            if  A[i]> positive_nus[0]:
                positive_nus[2] = positive_nus[1]
                positive_nus[1]= positive_nus[0]
                positive_nus[0] = A[i]
            elif  A[i] > positive_nus[1]:
                positive_nus[2] = positive_nus[1]
                positive_nus[1]= A[i]
            elif  A[i] > positive_nus[2]:
                positive_nus[2] = A[i]
            if A[i] < negative_nus[0]:
                negative_nus[1] = negative_nus[0]
                negative_nus[0] = A[i]
            elif A[i] < negative_nus[1]:
                negative_nus[1] = A[i]

    sol1 = positive_nus[0]*positive_nus[1]*positive_nus[2]
    sol2 = positive_nus[0]*negative_nus[0]*negative_nus[1]
    return  max(sol1,sol2)

答案 11 :(得分:0)

enter image description here

python 3,谢谢DanutClapa,我对正数的理解很好,但是您对最后2个负数的澄清才是解决方案。

def solution(arr):

    if not arr:
        return 0

    if len(arr) == 3:
        m   = 1
        for i in arr:
            m *= i
        return m
    else:
        max_num       = min(arr)
        second_max    = min(arr)
        tercero_max   = min(arr)

        min_num       = max(arr)
        min_num_2     = max(arr)

        for i in range(0, len(arr)):

            if (arr[i] > max_num):
                tercero_max = second_max
                second_max  = max_num
                max_num     = arr[i]
            elif arr[i] > second_max:
                tercero_max = second_max
                second_max  = arr[i]
            elif arr[i] > tercero_max:
                tercero_max = arr[i]

            if arr[i] < min_num:
                min_num_2 = min_num
                min_num   = arr[i]
            elif arr[i] < min_num_2:
                min_num_2 = arr[i]

        return max( max_num * second_max * tercero_max,     max_num * min_num * min_num_2)

答案 12 :(得分:0)

@SlobodanAntonijević答案中的JavaScript解决方案

function solution(A) {
    let N = A.length;
    /* some time sort doesn't work as expected try passing your own 
     sorting function to sort it in ascending order
    */
    A = A.sort((a,b) => (a-b));
    return Math.max(A[0] * A[1] * A[N - 1], A[N - 1] * A[N - 2] * A[N - 3]);
}

答案 13 :(得分:0)

没有排序... ES6,但老实说:为什么没有排序?

  1. 找到最大数量{max [0]> max [1]> max [2]}
  2. 找到2个最小的{min [0]
  3. 返回[max [0] * max [1] * max [0],max [0] * max [1] * max [2]]的最大值
if (['click', 'keydown'].includes(event.type)) { // Code Implementation Here}

答案 14 :(得分:0)

可以在Codility问题中使用排序。这是一个100%的解决方案。如果没有排序,它就会变得混乱,但绝对可能。

enter image description here

#include<limits>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int solution(vector<int> &A) {
    int abs1 = numeric_limits<int>::min();
    int abs2 = numeric_limits<int>::min();
    sort(A.begin(), A.end());
    unsigned int size = A.size()-1;
    int temp;
    for (unsigned int i = 0; i <= size ; ++i) {
        if(A[i] > 0 ) continue;
        if(abs(A[i]) >= abs1 ) {
            temp = abs1;
            abs1 = abs(A[i]);
            abs2 = temp;
        }else if(abs(A[i]) >= abs2 ) {
            abs2 = abs(A[i]);
        }
    }
    return max(A[size] * A[size-1] * A[size-2], abs1 * abs2 * A[size]);
}


int main(){
    vector<int> test = {-4, -6, 3, 4, 5};
    cout << solution(test);
    return 0;
}

答案 15 :(得分:0)

private static int[] rev(int[] validData) {
    for (int i = 0; i < validData.length / 2; i++) {
        int temp = validData[i];
        validData[i] = validData[validData.length - i - 1];
        validData[validData.length - i - 1] = temp;
    }
    return validData;
}

public static int solution(int[] A) {
    // write your code in Java SE 8
    long p = 0, q = 0, r = 0, max1 = Integer.MAX_VALUE, max2 = Integer.MAX_VALUE, res = 0;

    Arrays.sort(A);
    A = rev(A);
    int start = 0, end = A.length;

        //upper bound
        p = A[start];
        q = A[start + 1];
        r = A[start + 2];
        max1 = p * q * r;


        //lower bound

        q = A[end - 1];
        r = A[end - 2];
        max2 = p * q * r;


    return (int) Math.max(max1, max2);
}

有点晚了,但这种方法效率较低,但仍然很快。它反转数组,然后逻辑是,上限是第一个元素*两个连续性,或者第一个元素*两个最后连续,两个中的任何一个应该产生最大值。

答案 16 :(得分:-1)

这是我的c#解决方案。首先对数组进行排序,以获取所需的最大乘积max整数。 对于负整数,我们需要查看排序数组的前两个元素。 此解决方案可获得100%

public int solution(int[] A)
{ 
    var sorted = A.ToList(); 
    sorted.Sort(); 

    var last = sorted[sorted.Count-1]*sorted[sorted.Count-2]*sorted[sorted.Count-3];
    var firsttwo = sorted[0]*sorted[1]*sorted[sorted.Count-1];

    return Math.Max(last,firsttwo);
}

答案 17 :(得分:-1)

如果有人在乎C。 我之前尝试过quicksort,但由于性能问题获得了88%的结果。 所以我最终得到了一个高效的(100%)但凌乱的代码: https://app.codility.com/demo/results/trainingGT8RQR-FBM/

    int solution(int A[], int N) {


    int NEG[3]; NEG[0]=0; NEG[1] = 0; NEG[2]=0;    int p=-1;
    int POS[3]; POS[0] = 0; POS[1] =0; POS[2] = 0; int n=-1;
    int MAXIM[3]; MAXIM[0]=-1001; MAXIM[1]=-1001; MAXIM[2]=-1001; int m = -1;

    int i =0;

    for(i = 0 ; i < N ; i++)
    {
        if(A[i] < 0 && A[i] < NEG[2])
        {
            if(A[i] < NEG[0]) { NEG[2] = NEG[1]; NEG[1] = NEG[0];NEG[0] = A[i];}
            else if(A[i] < NEG[1]) { NEG[2] = NEG[1]; NEG[1] = A[i];}
            else if(A[i] < NEG[2]) NEG[2] = A[i];
            if(n < 2) n++;
        }        
        else if(A[i] >= 0 && A[i] > POS[2])
        {
        
            if(A[i] > POS[0]) {POS[2] = POS[1]; POS[1] = POS[0]; POS[0]=A[i];}
            else if(A[i] > POS[1]) {POS[2] = POS[1]; POS[1] = A[i];}
            else POS[2] = A[i]; 
            if(p < 2) p++;
        }

        if(A[i] <= 0 )
        {
        if(A[i] > MAXIM[0]){ MAXIM[2]=MAXIM[1];MAXIM[1]=MAXIM[0]; MAXIM[0]=A[i]; if(m<2)m++;}
        else if(A[i]>MAXIM[1]){MAXIM[2]=MAXIM[1]; MAXIM[1]=A[i];if(m<2)m++;}
        else if(A[i]>MAXIM[2]){MAXIM[2]=A[i]; if(m<2)m++;}
        
        
        }
    }

    int max =0, val_set =0;;
    if( n >=1 && p>=0 )
    {
        int tmp = NEG[0] * NEG[1] * POS[0];
        if(val_set == 0)
            { max = tmp;
                val_set =1;
            }
        else    
        if(tmp > max){
            max = tmp;
        } 
    }
    if( p > 1 )
    {
        int tmp = POS[0] * POS[1] * POS[2];
        if(val_set == 0)
            { max = tmp;
                val_set =1;
            }
        else
        if(tmp > max )
            {max = tmp;}
    } 
    else
    if( n > 1)
    {
        int tmp = NEG[0] * NEG[1] * NEG[2];
        if(val_set == 0)
            { max = tmp;
                val_set =1;
            }
        else
        if(tmp > max ){
            max = tmp;}
    }
    if(m>1){
    int temp = MAXIM[0] * MAXIM[1] * MAXIM[2];
           if(val_set == 0)
            { max = temp;
                val_set =1;
            }
        else if(temp > max){
        max = temp;}
    }  
    return max;
}