java 有序列表_关于算法:在Java中为列表列表生成唯一的有序非重复组合

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

我有列表列表(list >),列表可以是任何大小。

例:

我的外部列表大小是: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个是唯一的,其余都是重复项。

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

all-domain-sets-union的累积集积可以创建所有可能的组合,并且没有重复项

1:这是作业吗?

2:您预计最多使用几个列表?

基本上...将不会有某种神奇的方法来执行此操作...您将不得不检查所构建的字符串是否已经包含要考虑添加的字母,这就是您要优化-检查您的字符串是否已经包含字母。

如果您正在做家庭作业,我认为您可以使用String.contains('a')|| String.contains('A')以查看String是否已经包含某个字母(在这种情况下为'a')。剩下的我留给你。请注意,这是O(n ^ 2)运算。

如果您是为了更工业应用而这样做,那么我会看到另一个选择。

如果要使用大量的字符串列表,则可能需要使用TreeSet来存储已经使用过的字符列表。例如,浏览完第一个列表(a,b,c)后,您将看到"二手字符"的树集是否包含" a",否则,您将在字符串中添加" a"并在使用的字符的TreeSet中添加" a"。然后,您将转到第二个列表,查看您的TreeSet是否包含字母d,依此类推。总的来说,这将是一个o(n * log(n))函数。

使用TreeSet来存储"已用"字符列表的好处是,使用o来添加和检查字符要花费o(log(n)),而使用o来检查String中的字符要花费o(n)。 contains(" a")。 (您甚至可以在添加/检查之前将所有内容都转换为小写。)

使用TreeSet的缺点是,仅实例化TreeSet会产生适度的开销,如果仅使用小的字符串列表,则可能不值得。

问题:为什么要有一个字符串列表而不是一个字符列表?似乎字符列表更合适。

如果您不熟悉o(n ^ 2),o(log(n))或o(n)的含义,那么o(whatever)只是一种近似表示函数运行时间如何扩展的表示法以及传递给该函数的参数数量。

-例如,如果您运行带有4个参数的o(n ^ 2)函数,则将花费4 ^ 2 == 16时间(其中"时间"是任意时间单位)。如果使用8个参数运行它,则将花费8 ^ 2 == 64时间。随着输入大小的增加,它会平方增加。

-例如,如果您运行带有4个参数的o(n)函数,它将执行4次。如果您运行带有8个参数的o(n)函数,则将花费8次。

-例如,如果您运行带有4个参数的o(log(n))函数,则将花费2倍的时间。如果您运行带有8个参数的o(log(n))函数,则将花费3倍的时间。 (假设日志以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倍。

谢谢回复。实际上,它是具有更多内容的对象列表(域类代表一个表),它是一项业务需求并且是机密的,因此我使用字母并将其引用为List >而不是List >。我预计最多可以有20个内部列表,但是每个内部列表的大小最大为30。..问题是,当我得到更大的列表时,处理List >需要2到5分钟,我可能最多20000列表>。因此需要100多个小时才能完成。需要逻辑在3到4个小时内处理

嗯。今天上班时我有个主意。如果您有20个内部列表,我想我知道一种使用递归算法使其运行速度快19倍的方法(与仅对20个内部列表进行天真的迭代相比)。此外,使用TreeSet可能会使它运行快2倍。最后,我在Intel i7 930上使用多线程处理器的经验表明,尽管您将使用几乎所有的CPU容量,但您可以使处理器运行速度提高5倍(ish)。所以...希望我们可以减少您的时间。等待第二篇关于递归思想的文章。

你知道什么...我应该更了解。这个问题是NP难题。在大小为5的10个内部列表上运行大约需要5.6秒,但将其跳至11则需要28秒。 12个内部列表需要137秒。 (由于每个内部列表都有5个字符,因此添加的每个内部列表都会增加5倍。)

我彻底被淘汰了。问题是NP难的。建议您找到一种不同的方式来做您想做的事。

编辑:只需重新阅读您的原始帖子即可。昨晚我看完之后好像您已对其进行了编辑……我现在看到您不是在要求以下算法,而是在要求其他东西。 = /会考虑的,但可能什么也不会想出来。

public static void main(String[] args) {

long runningTime = 0;

int numTrials = 1;

for( int i = 0; i < numTrials; i++ )

{

List> 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> theLists;

private Stack buildingString;

private TreeSet usedChars;

public RecursiveAnalyzer( List> newTheLists )

{

this.theLists = newTheLists;

}

public void run()

{

this.usedChars = new TreeSet<>();

this.buildingString = new Stack<>();

recursiveAnalysisHelper( 0 );

}

protected void recursiveAnalysisHelper( int currentDepth )

{

List 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> makeListOfLists( int numLists, int numChars )

{

List> answer = new ArrayList<>();

Random rand = new Random();

if ( numChars > 25 )

{

numChars = 25;

}

for( int i = 0; i < numLists; i++ )

{

List 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;

}

感谢您为我提供更好解决方案的努力。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值