对于某些正整数i,j
,我需要使用0 <= i < n
,0 <= j < n
和i < j
遍历所有对n
。
问题是我只能循环遍历另一个变量,比如k
。我可以控制k
的界限。所以问题是要确定两个算术方法f(k)
和g(k)
,以便i=f(k)
和j=g(k)
遍历所有可接受的对,因为k
遍历其连续值。< / p>
我怎样才能以简单的方式做到这一点?
答案 0 :(得分:3)
我想我得到了它(在Python中):
def get_ij(n, k):
j = k // (n - 1) # // is integer (truncating) division
i = k - j * (n - 1)
if i >= j:
i = (n - 2) - i
j = (n - 1) - j
return i, j
for n in range(2, 6):
print n, sorted(get_ij(n, k) for k in range(n * (n - 1) / 2))
它基本上折叠矩阵,使其(几乎)呈矩形。几乎&#34;几乎&#34;我的意思是在最底行的最右边可能有一些未使用的条目。
以下图片说明折叠如何适用于n = 4:
和n = 5:
现在,迭代矩形很容易,就像从折叠坐标映射回原始三角矩阵中的坐标一样。
优点:使用简单的整数数学。
缺点:以奇怪的顺序返回元组。
答案 1 :(得分:3)
我认为我发现了另一种方式,它以字典顺序给出对。请注意,i > j
代替i < j
。
基本上算法由两个表达式组成:
i = floor((1 + sqrt(1 + 8*k))/2)
j = k - i*(i - 1)/2
将i,j
作为k
的函数。这里k
是一个从零开始的索引。
优点:以字典顺序给出对。
缺点:依赖于浮点运算。
<强>理由:强>
我们希望在下表中实现映射:
k -> (i,j)
0 -> (1,0)
1 -> (2,0)
2 -> (2,1)
3 -> (3,0)
4 -> (3,1)
5 -> (3,2)
....
我们首先考虑逆映射(i,j) -> k
。要意识到这一点并不难:
k = i*(i-1)/2 + j
自j < i
以来,k
对应于具有固定(i,j)
的所有对i
的值满足:
i*(i-1)/2 <= k < i*(i+1)/2
因此,给定k
,i=f(k)
会返回i
这样的最大整数i*(i-1)/2 <= k
。经过一些代数:
i = f(k) = floor((1 + sqrt(1 + 8*k))/2)
我们找到值i
后,j
可以通过
j = k - i*(i-1)/2
答案 2 :(得分:0)
我不确定完全理解这个问题,但总结一下,如果0&lt; = i&lt; n,0&lt; = j&lt; n,那么你想要遍历0&lt; = k&lt; N * N
for (int k = 0; k < n*n; k++) {
int i = k / n;
int j = k % n;
// ...
}
[编辑]我刚看到我&lt; j;所以,这个解决方案不是最优的,因为n * n必要的迭代次数就少了......
答案 3 :(得分:0)
如果我们根据数字三角形来考虑我们的解决方案,其中k
是序列
1
2 3
4 5 6
7 8 9 10
11 12 13 14 15
...
然后j
将是我们的(非零基础)行号,即最大整数,
j * (j - 1) / 2 < k
j
的
j = ceiling ((sqrt (1 + 8 * k) - 1) / 2)
i
行中k
&#39; s(从零开始)的位置
i = k - j * (j - 1) / 2 - 1
k
的界限是:
1 <= k <= n * (n - 1) / 2
答案 4 :(得分:0)
您实际上有两个算术函数f(k)和g(k)这样做很重要吗?因为您可以先创建一个列表,例如
L = []
for i in range(n-1):
for j in range(n):
if j>i:
L.append((i,j))
这将为您提供所有您需要的对。您的变量k现在可以沿着列表的索引运行。例如,如果我们取n = 5,
for x in L:
print(x)
给我们
(0,1), (0,2), (0,3), (0,4), (1,2), (1,3), (1,4), (2,3), (2,4), (3,4)
例如,假设您有2 <= k <5,则
for k in range(2, 5)
print L[k]
收益
(0,3), (0,4), (1,2)