简体   繁体   English

Java无限流中的通用元素

[英]Common element in Java infinite streams

I have three infinite Java IntStream objects. 我有三个无限的Java IntStream对象。 I want to find the smallest element that is present in all three of them. 我想找到所有这三个元素中存在的最小元素。

    IntStream a = IntStream.iterate(286, i->i+1).map(i -> (Integer)i*(i+1)/2);
    IntStream b = IntStream.iterate(166, i->i+1).map(i -> (Integer)i*(3*i-1)/2);
    IntStream c = IntStream.iterate(144, i->i+1).map(i -> i*(2*i-1));

I can always employ a brute force solution (without streams) which involves iterating in nested loops, but I was wondering if we can do it more efficiently with streams? 我总是可以采用蛮力解决方案(不使用流),该解决方案涉及在嵌套循环中进行迭代,但是我想知道我们是否可以使用流更有效地做到这一点?

You need to iterate all 3 in parallel, advancing the one with the lowest value, checking if all 3 are equal. 您需要并行地迭代所有3个对象,以最低的值前进一个对象,并检查所有3个对象是否相等。

You code will not find an answer for next value after 40755 , because the next value is 1_533_776_805 , which has intermediate value (before division by 2) higher than Integer.MAX_VALUE ( 2_147_483_647 ). 您的代码将找不到40755之后的下一个值的答案,因为下一个值是1_533_776_805 ,该中间值(除以2之前)比Integer.MAX_VALUE2_147_483_647 )高。

So, here is one way to use your streams, after changing them to long and guarding against overflow. 因此,在将流更改为long并防止溢出之后,这是使用流的一种方法。

LongStream a = LongStream.iterate(286, i->i+1).map(i -> Math.multiplyExact(i, i+1)/2);
LongStream b = LongStream.iterate(166, i->i+1).map(i -> Math.multiplyExact(i, 3*i-1)/2);
LongStream c = LongStream.iterate(144, i->i+1).map(i -> Math.multiplyExact(i, 2*i-1));

OfLong aIter = a.iterator();
OfLong bIter = b.iterator();
OfLong cIter = c.iterator();

long aVal = aIter.nextLong();
long bVal = bIter.nextLong();
long cVal = cIter.nextLong();
while (aVal != bVal || bVal != cVal) {
    long min = Math.min(Math.min(aVal, bVal), cVal);
    if (aVal == min)
        aVal = aIter.nextLong();
    if (bVal == min)
        bVal = bIter.nextLong();
    if (cVal == min)
        cVal = cIter.nextLong();
}
System.out.println(aVal);

These functions are always increasing. 这些功能一直在增加。 So the code should stop when the magic equal triplet is found. 因此,当找到相等的三元组时,代码应停止。

The thing to code is: 要编码的是:

a) when a stream's current value is below any other, it can iterate next for itself. a)当流的当前值低于任何其他值时,它可以自己进行下一个迭代。

b) when it meets the same candidate value, it waits for the 3rd stream to take a decision. b)当满足相同的候选值时,它等待第三流做出决定。

c) when it has a higher value than the all others, it changes the candidate and waits for both others. c)当其价值高于所有其他价值时,它将更改候选人并等待其他两个人。

Reference juggling. 参考杂耍。

There may not be a solution too (at least in short time). 可能也没有解决方案(至少在短时间内)。

Notice that stream c can only produce even numbers (when seeded with even). 请注意,流c只能产生偶数(当使用偶数进行播种时)。 There might be some optimization there to skip a and b faster. 可能有一些优化可以更快地跳过a和b。

I don't think there is anything smart possible with stream API. 我认为流API不可能有任何明智的选择。 The main reason is that you can't really go over one stream until some condition is met - instead, you look at current 3 elements and pick the next element from one of the streams before comparing the elements again. 主要原因是,在满足某些条件之前,您无法真正遍历一个流-而是查看当前的3个元素,并从一个流中选择下一个元素,然后再次比较这些元素。

The most efficient (and might be also the cleanest) solution is to use iterators and keep calling next() method on the right streams until the answer is found. 最有效(也是最干净的)解决方案是使用迭代器,并在正确的流上继续调用next()方法,直到找到答案为止。

To start with, you can focus on two streams only and find their first common value: 首先,您可以仅关注两个流并找到它们的第一个共同价值:

while (elementA != elementB) {
    if (elementA < elementB) {
        elementA = iteratorA.next();
    } else {
        elementB = iteratorB.next();
    }
}

Then you need to do make third stream catch up with these two: 然后,您需要使第三流赶上这两个:

while (elementC < elementA) {
    elementC = iteratorC.next();
}

At this point there are two options: 此时有两种选择:

  • either elementC == elementA in which case you have the answer 任一个elementC == elementA在这种情况下,您都有答案
  • or elementC > elementA in which case you can go to next value on all three streams and start over elementC > elementA在这种情况下,您可以在所有三个流上转到下一个值并重新开始

One thing to remember is the max value of integer. 要记住的一件事是整数的最大值。 Because you have i^2 , this means that it will overflow for i about 46k, so you need to change streams of ints to streams of longs (the answer is about 1.5 billion - and that's after division by 2 in these functions). 因为您有i^2 ,这意味着它将在i溢出约46k,因此您需要将int流更改为long流(答案约为15亿-并且在这些函数中被2除后)。

Since you are doing exercises for practice, I don't think it's right to give you the full working code, but let me know if you still struggle with it ;) 由于您正在练习练习,因此我认为向您提供完整的工作代码并不正确,但请告诉我您是否仍在努力;)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM