在java中为列表列表生成唯一有序的非重复组合

时间:2013-06-03 06:35:40

标签: java algorithm combinations

我知道有很多类似的问题,我已经阅读了几个小时。但它们似乎都不符合我的要求。

我有列表列表(列表< list< string>>)列表可以是任意大小。

示例:

我的外部列表大小为:4

列表的内容

 1. list(0) a,b,c                    size:3

 2. list(1) d,b,f,m                size:4

 3. list(2) x,a                           size:2

 4. list(3) b,e,d,m,a            size:5

这里我的组合将是

adxb

adxe 

adxd (adx) duplicate element will be removed after generating combination

adxm

adxa (adx)  

adab (adb)

adae (ade)

...

......等等

我必须从每个列表中选择一个元素来生成组合  组合长度最大为4(外部列表的大小),如果我在组合中获得相同的元素,有时会缩小

我的组合数量每个内部列表中元素数量的乘积。

在上面的示例中,组合数量为3x4x2x5=120种组合

由于我的列表包含重复元素,我也会得到重复的组合 如果我有 adab adba ,那么 adba 是重复的,因为订单无关紧要

问题是我使用直接的方法来生成组合,如果我的外部列表大小增加并且我的内部列表包含更多元素,我最终生成数百万的组合,但只有1000或2000将是唯一的休息所有重复。

是否有任何算法方法只能生成唯一的组合而不是生成所有组合?

2 个答案:

答案 0 :(得分:1)

1:这是家庭作业吗? 2:您预计使用多少个列表作为最大值?

基本上......不会有某种神奇的方式来做这件事......你将不得不检查你正在建造的字符串是否已包含你正在考虑添加的字母,这就是你想要优化的 - 检查你的String是否已经包含一个字母。

如果你这样做作业,我想你可以使用String.contains('a')|| String.contains('A')查看String是否已包含某个字母(在本例中为'a')。我会把剩下的留给你。请注意,这是一个O(n ^ 2)操作。

如果您正在为更多......工业应用做这件事,那么我会看到另一种选择。

如果您将拥有大量的String列表,那么您可能希望使用TreeSet来存储已经使用过的字符列表。例如,在浏览了第一个列表(a,b,c)之后,您将看到“used characters”的TreeSet是否包含“a”,如果不是,您将在String中添加“a”构建并将“a”添加到已使用字符的TreeSet中。然后,您将转到第二个列表,查看您的TreeSet是否包含字母d,依此类推。总的来说,这将是一个o(n * log(n))函数。

使用TreeSet存储“已使用”字符列表的好处是,添加和检查字符需要花费o(log(n))而不是o(n)来检查字符串中的字符使用String.contains(“a”)。 (您甚至可以在添加/检查之前将全部转换为小写。)

使用TreeSet的缺点是,在实例化TreeSet时会有一些适当的开销,如果你只使用小的字符串列表列表,它可能不值得。


问题:为什么你有一个字符串列表列表,而不是字符列表列表?看起来像一个字符列表更合适。


如果你不熟悉o(n ^ 2),o(log(n))或o(n)的意思,那么o(无论如何)只是一个表示近似运行时间的符号函数会随着传递给该函数的参数数量而扩展 - 例如,如果运行带有4个参数的o(n ^ 2)函数,则需要4 ^ 2 == 16时间(其中“time”是任意时间单位)。如果用8个参数运行它,则需要8 ^ 2 == 64次。随着输入尺寸的增加,它会以平方方式增加 - 例如,如果你运行带有4个参数的o(n)函数,它将是4次。如果运行带有8个参数的o(n)函数,则需要8次 - 例如,如果运行带有4个参数的o(log(n))函数,则需要2次。如果运行带有8个参数的o(log(n))函数,则需要3次。 (假设log是基数为2。)

希望你明白了 - 关键是o(n ^ 2),o(n * log(n)),o(n)和o(log(n))之间的差异很小小数字,但是一旦你开始得到大小为100或更多的列表,它将是重要的 - o(n ^ 2)将花费10,000次并且o(n * log(n))将花费大约670次 - 也就是说,它只有100个列表快15倍。在1000个列表中,它将快100倍。

答案 1 :(得分:0)

我完全被击败了。问题是NP难的。建议你找到一种不同的方式去做你想做的事情。

编辑:重新阅读原帖。看起来就像你昨晚读完它后编辑的那样...我现在看到你不是要求下面的算法,而是要求别的东西。 = /会想一想,但可能不会想出任何东西。

public static void main(String[] args) {

    long runningTime = 0;
    int numTrials = 1;

    for( int i = 0; i < numTrials; i++ )
    {
        List<List<String>> theLists = UniqueStringTest.makeListOfLists(12, 5);

        long startTime = System.currentTimeMillis();
        RecursiveAnalyzer ra = new RecursiveAnalyzer( theLists );
        ra.run();
        runningTime += ( System.currentTimeMillis() - startTime );

    }

    System.out.println( "Finished " + numTrials + " trials in " + 
                        runningTime + " milliseconds." );

}

public static class RecursiveAnalyzer implements Runnable
{

    private List<List<String>> theLists;
    private Stack<String> buildingString;
    private TreeSet<String> usedChars;

    public RecursiveAnalyzer( List<List<String>> newTheLists )
    {
        this.theLists = newTheLists;
    }

    public void run()
    {
        this.usedChars = new TreeSet<>();
        this.buildingString = new Stack<>();

        recursiveAnalysisHelper( 0 );
    }

    protected void recursiveAnalysisHelper( int currentDepth )
    {
        List<String> currentList = this.theLists.get( currentDepth );
        boolean haveOneOnStack = false;

        //Iterate over each character in list number currentDepth
        for( int i = 0; i < currentList.size(); i++ )
        {
            if ( this.usedChars.contains( currentList.get(i) ) == false )
            {
                this.usedChars.add( currentList.get(i) );
                this.buildingString.push( currentList.get(i) );
                haveOneOnStack = true;
            }
            else
            {
                haveOneOnStack = false;
            }

            if ( (currentDepth+1) < this.theLists.size() )
            {
                recursiveAnalysisHelper( currentDepth+1 );
            }
            else
            {
                String answer = "";
                for( String s : this.buildingString )
                {
                    answer += s;
                }
                //System.out.println(answer);
            }

            if( haveOneOnStack == true )
            {
                this.buildingString.pop();
                this.usedChars.remove( currentList.get(i) );
            }

        }

    }
}

public static List<List<String>> makeListOfLists( int numLists, int numChars )
{
    List<List<String>> answer = new ArrayList<>();
    Random rand = new Random();
    if ( numChars > 25 )
    {
        numChars = 25;
    }

    for( int i = 0; i < numLists; i++ )
    {
        List<String> anInnerList = new ArrayList<>();
        for( int j = 0; j < numChars; )
        {
            //Makes a lowercase letter
            String aChar = Character.toString((char)(rand.nextInt(26)+97));
            if ( anInnerList.contains( aChar ) == false )
            {
                anInnerList.add( aChar );
                j++;
            }
        }
        answer.add(anInnerList);
    }

    return answer;
}