如何在Java中以更优化的方式生成数字组合?

时间:2017-10-30 09:21:38

标签: java numbers combinations triplet

我有一个问题陈述,需要将3个不同的数字传递给方法,并检查哪3个数字满足某个约束。

这是我的代码,但我想知道而不是创建嵌套循环,是否有更优化的方法来检查哪一组三元组满足某个约束。 ?

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Solution
{

    static List l = new ArrayList();

    static int geometricTrick(String s)
    {
        int count = 0;

        for (int i = 0; i < s.length(); i++)
        {
            for (int j = 0; j < s.length(); j++)
            {
                for (int k = 0; k < s.length(); k++)
                {
                    if (is1stConstraintTrue(s, i, j, k) && is2ndConstraintTrue(i, j, k))
                    {
                        l.add(new Triplet(i, j, k));
                    }
                }
            }
        }

        count = l.size();

        return count;

    }

    static boolean is2ndConstraintTrue(int i, int j, int k)
    {
        boolean retVal = false;

        double LHS = Math.pow((j + 1), 2);

        double RHS = (i + 1) * (k + 1);

        if (LHS == RHS)
            retVal = true;
        else
            retVal = false;

        return retVal;
    }

    static boolean is1stConstraintTrue(String s, int i, int j, int k)
    {
        boolean retVal = false;

        char[] localChar = s.toCharArray();

        if (localChar[i] == 'a' && localChar[j] == 'b' && localChar[k] == 'c')
        {
            retVal = true;
        }

        return retVal;
    }

    static class Triplet
    {
        public int i, j, k;

        public Triplet(int i, int j, int k)
        {
            this.i= i;
            this.j= j;
            this.k= k;
        }
    }
    public static void main(String[] args)
    {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        String s = in.next();
        int result = geometricTrick(s);
        System.out.println(result);

    }
}

3 个答案:

答案 0 :(得分:0)

以下是一些提示:

  1. 通过乘法计算平方将比使用pow

  2. 更快
  3. String::toCharray()很贵。它将所有字符复制到一个新数组中。每次你打电话。不要多次打电话。

  4. 如果结果是三元组的数量,则不需要构建列表。您甚至不需要创建Triple个实例。算一算吧。

  5. 如果需要迭代所有组合,嵌套循环效率不高。

答案 1 :(得分:0)

为您提供一个简单的&#34;愚蠢的&#34;不使用那些内循环的解决方案。

让我们像Iterator一样使用工厂。这将隐藏&#34;使用条件语句循环。

public class TripletFactory{

    final int maxI, maxJ, maxK;
    int i, j ,k;

    public TripletFactory(int i, int j, int k){
        this.maxI = i;
        this.maxJ = j;
        this.maxK = k;
    }

    public Triplet next(){
        if(++k > maxK){
            k = 0;
            if(++j > maxJ){
                j = 0;
                if(++i > maxI){
                    return null;
                }
            }
        }
        return new Triplet(i,j,k);
    }
}   

这样,您只需要获得一个新的Triple,直到一个循环中的null个实例

TripletFactory fact = new TripletFactory(2, 3 ,5);

Triplet t = null;
while((t = fact.next()) != null){
    System.out.println(t);
}
//no more Triplet

并按照您的意愿使用它。

然后,您必须更新约束方法以获取Triplet并使用getters检查实例。

这可能是Triplet允许它顺便验证自己的方法。

注意:

我使用了与Iterator相同的表示法,因为我们可以实现IteratorIterable来使用如下符号:

for(Triplet t : factory){
    ...
}

答案 2 :(得分:0)

您提出的天真方法具有三次时间复杂度(三个嵌套for - 循环)。如果您在输入中出现过多次'a''b''c',那么首先确定所有'a'的索引可能是值得的, 'b'&{39}和'c'&#39;然后只检查您的第二个条件。

import java.util.ArrayList;
import java.util.List;

public class Main {

    public static List<Integer> getAllOccurrences(String input, char of) {
        List<Integer> occurrences = new ArrayList<Integer>();
        char[] chars = input.toCharArray();

        for (int idx = 0; idx < chars.length; ++idx) {
            if (of == chars[idx]) {
                occurrences.add(idx);
            }
        }

        return (occurrences);
    }

    static List<Triplet> geometricTrick(String input){
        List<Integer> allAs = getAllOccurrences(input, 'a');
        List<Integer> allBs = getAllOccurrences(input, 'b');
        List<Integer> allCs = getAllOccurrences(input, 'c');
        List<Triplet> solutions = new ArrayList<Triplet>();

        // reorder the loops, so that the c-loop is the innermost loop (see
        // below why this is useful and how it is exploited).
        for (int a : allAs) {
            for (int c : allCs) {
                // calculate lhs as soon as possible, no need to recalculate the
                // same value multiple times
                final int lhs = ((a + 1) * (c + 1));

                for (int b : allBs) {
                    final int rhs = ((b + 1) * (b + 1));
                    if (lhs > rhs) {
                       continue;
                    }

                    /* else */ if (lhs == rhs) {
                        solutions.add(new Triplet(a, b, c));
                    }

                    // by construction, the b-values are in ascending or der.
                    // Thus if the rhs-value is larger or equal to the
                    // lhs-value, we can skip all other rhs-values. for this
                    // lhs-value.

                    // if (lhs <= rhs) {
                        break;
                    // }
                }
            }
        }
        return (solutions);
    }

    static class Triplet {

        public final int i;
        public final int j;
        public final int k;

        public Triplet(int i, int j, int k) {
            this.i = i;
            this.j = j;
            this.k = k;
        }
    }
}

在给定char内搜索所有出现的String需要O(n)(方法getAllOccurrences(...)),调用它三次不会改变复杂性(3 * n \ in上))。迭代abc的所有可能组合需要#a *#b *#c时间,其中#{{ 1}},#a和#b会计入ca&{39}和b& #39;在c中。这使得总时间复杂度为O(n +#input *#a *#b)。

请注意,最糟糕的情况是时间复杂,即如果您的字符串的1/3由c组成,则1/3由a组成,并且1 / 3由b组成,仍然是立方体。