ThreeSum問題

1861 ワード

public class ThreeSum{
    public static int count(int[] a){
        int N = a.length;
        int cnt = 0;
        for (int i=0; i< N; i++)
            for( int j=i+1; j

ThreeSum問題:すべての異なる整数の三元グループの和を計算し、統計し、0の数にする.上記のコードは最も簡単で直接的な解法である.
簡単な改良により,より優れたアルゴリズムを容易に実現でき,集計ソートと二分検索を利用することができる.まず問題を簡略化し、TwoSum問題を考慮してみてください.TwoSum問題も2乗レベルの解決を容易に実現することができます.2層サイクルで暴力的に解くことができますが、集計ソートと2点検索を通じて、線形対数レベルでTwoSum問題を解決します.
import  java.util.Arrays;
public class TwoSumFast{
    public static int count(int[] a){
        Arrays.sort(a);
        int N = a.length;
        int cnt = 0;
        for(int i = 0; i < N; i++)
            if(BinarySearch.rank(-a[i], a) > i)
                cnt++;
        return cnt;
    }
    public static void main(String[] args){
    int[] a = In.readInts(args[0]);
    StdOut.println(count(a));
    }
}

改良されたアルゴリズム思想は、−a[i]が配列中に存在し(かつa[i]がゼロではない)場合にのみ、a[i]がある和がゼロの整数対中に存在する場合である.まず配列を並べ替え,配列内の各a[i]についてBinarySearchのrank()法を用いて−a[i]を二分的に検索した.集計ソートに要する時間はNlognに比例し,二分検索に要する時間はlognに比例するため,総時間はNlognに比例する.この方式は3−sum問題に対しても同様に有効であり、−(a[i]+a[j])が配列中に存在する場合にのみ、整数対a[i]およびa[j]は、ある和がゼロの三元配列の一部である.
import java.util.Arrays;
public class ThreeSumFast{
    public static int count(int[] a){
        Arrays.sort(a);
        int N = a.length;
        int cnt = 0;
        for(int i = 0; i < N; i++)
            for(int j = i+1; j < N; j++)
                if(BinarySearch.rank(-a[i]-a[j],a) > j)
                    cnt++;
        return cnt;
    }
    public static void main(String[] args){
          int[] a = In.readInts(args[0]);
          StdOut.println(count(a));
    }
}

検索ごとの時間はlognに比例するので、総実行時間はN²lognが比例する.