Ordered cartesian product of arrays
在2个整数排序数组的高效排序笛卡尔积中,建议使用惰性算法生成两个整数排序数组的有序笛卡尔积。
我很想知道这个算法是否可以推广到更多的数组中。
例如,假设我们有5个排序的双精度数组
(0.7、0.2、0.1)
(0.6、0.3、0.1)
(0.5、0.25、0.25)
(0.4、0.35、0.25)
(0.35、0.35、0.3)
我对生成有序笛卡尔积感兴趣,不必计算所有可能的组合。
请欣赏任何关于可能的懒惰笛卡尔积算法如何扩展到2以外的维度的想法。
这个问题似乎是统一成本搜索的枚举实例(参见https://en.wikipedia.org/wiki/dijkstra%27s_算法)。状态空间由指向已排序数组的当前索引集定义。后继函数是每个数组的可能索引增量的枚举。对于5个数组的给定示例,初始状态为(0、0、0、0、0)。
没有目标状态检查功能,因为我们需要经历所有可能的过程。如果对所有的输入数组进行排序,则保证对结果进行排序。
假设我们有m个长度为n的数组,那么这个方法的复杂性是o((n^m).log(n(m-1))。
下面是Python中的示例实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | from heapq import heappush, heappop def cost(s, lists): prod = 1 for ith, x in zip(s, lists): prod *= x[ith] return prod def successor(s, lists): successors = [] for k, (i, x) in enumerate(zip(s, lists)): if i < len(x) - 1: t = list(s) t[k] += 1 successors.append(tuple(t)) return successors def sorted_product(initial_state, lists): fringe = [] explored = set() heappush(fringe, (-cost(initial_state, lists), initial_state)) while fringe: best = heappop(fringe)[1] yield best for s in successor(best, lists): if s not in explored: heappush(fringe, (-cost(s, lists), s)) explored.add(s) if __name__ == '__main__': lists = ((0.7, 0.2, 0.1), (0.6, 0.3, 0.1), (0.5, 0.25, 0.25), (0.4, 0.35, 0.25), (0.35, 0.35, 0.3)) init_state = tuple([0]*len(lists)) for s in sorted_product(init_state, lists): s_output = [x[i] for i, x in zip(s, lists)] v = cost(s, lists) print '%s %s \t%s' % (s, s_output, cost(s, lists)) |
所以,如果你有a(a1,…,a)和b(b1,…,bn)。
A
A1*…*An 我假设每个值都是正数,因为如果我们允许负数,那么: (-50,-100,1)>(1,2,3) as-50*(-100)*1=5000>6=1*2*3 即使没有负值,问题仍然相当复杂。您需要一个包含数据结构的解决方案,其深度为k。如果(a1,…,ak)<(b1,…,bk),那么我们可以假设在其他维度上(a1,…,ak,…)的组合。a)可能小于(b1,…,bk,…,bn)的组合。因此,如果这不是真的,情况就超过了概率,所以这些都是规则的例外。数据结构应包含:
- K
- A和B的前k元素
- 规则例外的描述
对于任何此类例外情况,可能存在大于(b1,…,bk)的(c1,…,ck)组合,但(c1,…,ck)的较大组合可能仍然具有使用进一步维度值的组合,其中(a1,…,ak)<(c1,…,ck)规则的例外可能仍然存在。
因此,如果您已经知道(a1,…,ak)<(b1,…,bk),那么首先您必须通过查找第一个l维来检查是否存在异常,在这里,选择a的最大可能值和b的最小可能值。如果存在这样的l,那么您应该找到异常的开始位置(哪个维,哪个索引)。这将描述异常情况。当你发现异常时,你知道(a1,…,ak,…,al)>(b1,…,bk,…,bl)的组合,所以这里的规则是a大于b,当b大于a时会出现异常。
为了反映这一点,数据结构如下:
1 2 3 4 5 6 | class Rule { int k; int[] smallerCombinationIndexes; int[] biggerCombinationIndexes; List<Rule> exceptions; } |
每当您发现一个规则的异常时,该异常将基于先前的知识生成。不用说,复杂性大大增加了,但问题是您对规则有异常,对异常有异常等等。当前的方法会告诉你,如果你取两个随机点,A和B,A是否小于B,它也会告诉你,如果你取(a1,…,ak)和(b1,…,bk)的组合,那么(a1,…,ak)和(b1,…,bk)的比较结果会改变的关键指标是什么。根据您的具体需求,这个想法可能已经足够,或者需要扩展。因此,您的问题的答案是:是的,您可以扩展lazy算法来处理进一步的维度,但是您需要处理规则的异常来实现这一点。