【问题标题】:From a loop index k, obtain pairs i,j with i < j?从循环索引 k 中,获得 i < j 的对 i,j?
【发布时间】:2014-11-25 13:35:32
【问题描述】:

我需要遍历所有对 i,j0 &lt;= i &lt; n0 &lt;= j &lt; ni &lt; j 以获得一些正整数 n

问题是我只能遍历另一个变量,比如k。我可以控制k 的范围。所以问题是确定两种算术方法,f(k)g(k) 使得i=f(k)j=g(k) 遍历所有允许的对,因为k 遍历其连续值。

我怎样才能以简单的方式做到这一点?

【问题讨论】:

  • 遍历顺序重要吗?如果是,请指定所需的顺序。
  • @NPE 遍历顺序无关紧要,只要所有对都只遍历一次即可。
  • 这是你要找的{(f(k), g(k)) | 0 &lt;= f(k) &lt; n, 0 &lt;= g(k) &lt; n, f(k) &lt; g(k) }吗? k的界限是多少?什么是 f(k) 和 g(k)?
  • @LoganMurphy 是的。我们想要一个方法F(k)(=(f(k),g(k))),它接受k并返回一对(i,j),这样i &lt; j0&lt;=i&lt;n0&lt;=j&lt;n,当k取值在一个合适的范围内时,所有这些对只出现一次。
  • 有趣的问题。有些东西告诉我,这可能有一个优雅的算法,但我正在努力想出一个。 :-)

标签: algorithm loops matrix mapping integer-arithmetic


【解决方案1】:

我不确定是否完全理解这个问题,但总结一下,如果 0

for (int k = 0; k < n*n; k++) {
    int i = k / n;
    int j = k % n;
    // ...
}

[edit] 我刚刚看到 i

【讨论】:

  • 没错,如果不是i &lt; j 限制,这将是解决方案。我怀疑实际的解决方案不会离这个太远
【解决方案2】:

我想我明白了(在 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))

它基本上将矩阵折叠成(几乎)矩形。 “几乎”是指底行最右侧可能有一些未使用的条目。

下图说明了 n=4 的折叠方式:

并且 n=5:

现在,遍历矩形很容易,从折叠坐标映射回原始三角矩阵中的坐标也是如此。

优点:使用简单的整数数学。

缺点:以奇怪的顺序返回元组。

【讨论】:

    【解决方案3】:

    我想我找到了另一种方法,即按字典顺序给出对。注意这里是i &gt; j 而不是i &lt; 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) -&gt; k。不难发现:

    k = i*(i-1)/2 + j

    由于j &lt; i,所以k对应所有对(i,j)和固定i的值满足:

    i*(i-1)/2 <= k < i*(i+1)/2
    

    因此,给定ki=f(k) 返回最大整数i,使得i*(i-1)/2 &lt;= k。经过一些代数:

    i = f(k) = floor((1 + sqrt(1 + 8*k))/2)
    

    在我们找到i 的值后,j 被简单地给出

    j = k - i*(i-1)/2
    

    【讨论】:

    • 很高兴看到证明/推导/插图以了解其工作原理。第二行看起来很清楚,但第一行有点神秘(至少对我疲惫的昏昏欲睡的大脑来说)。
    • @NPE 我会写一些东西。我只是想先把它弄清楚。
    • 我已经对此进行了简短的测试,它似乎确实有效(以我尚未测试或考虑过的浮点数学的任何潜在问题为模)。
    • @NPE 添加了一些解释。
    【解决方案4】:

    如果我们用数字三角形来考虑我们的解决方案,其中k 是序列

    1 
    2  3 
    4  5  6 
    7  8  9  10
    11 12 13 14 15
    ...   
    

    那么j 将是我们的(非从零开始的)行号,即最大整数使得

    j * (j - 1) / 2 < k
    

    Solvingj

    j = ceiling ((sqrt (1 + 8 * k) - 1) / 2)
    

    i 将是k 在行中的(从零开始的)位置

    i = k - j * (j - 1) / 2 - 1
    

    k 的范围是:

    1 <= k <= n * (n - 1) / 2 
    

    【讨论】:

      【解决方案5】:

      实际上有两个算术函数 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

      for k in range(2, 5)
          print L[k]
      

      产量

      (0,3), (0,4), (1,2)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-04-19
        • 1970-01-01
        • 2012-10-20
        • 2021-04-09
        • 1970-01-01
        • 2023-04-05
        • 2013-08-19
        相关资源
        最近更新 更多