Python:输出总和为目标总和的所有范围

Ril*_*Hun 1 python arrays algorithm data-structures

题:

给定 K 由非零、非负整数 1 到 K 组成,输出总和等于 K 的所有范围/区间。

例如,如果 K 等于 6,那么输出应该是[[1,3], [6,6]]。对于[1,3], 1+2+3 = 6 和 对于[6,6], 6 = 6。

我的解决方案

下面是我的解决方案,但我认为时间复杂度是 O(N2)。有没有更有效的方法来做到这一点?

def targetSum(k):
  nums = list(range(1,k+1))
  res = []
  for end in range(len(nums)):
    start = 0
    while start <= end:
      sumhere = sum(nums[start:end+1])
      if sumhere == k:
        res.append([nums[start], nums[end]])
      start+=1
  return res

targetSum(6)
Run Code Online (Sandbox Code Playgroud)

MBo*_*MBo 6

您可以O(sqrt(K))使用一些数学方法及时解决此问题。

范围和是差1的等差数列之和,所以我们可以写公式

K = n/2 * (2*a + n - 1) or
2 * K = n * (2*a + n - 1) 
Run Code Online (Sandbox Code Playgroud)

其中n是范围大小,a是起始值

所以我们遍历所有可能的因式分解2*K成两个因数2*K = p * q ,并求解简单系统

n = p
2*a + n - 1 = q
Run Code Online (Sandbox Code Playgroud)

或者

2*a + p - 1 = q
a  = (q + 1 - p) / 2
Run Code Online (Sandbox Code Playgroud)

请注意,解决方案存在于不同奇数/偶数/奇偶性的除数(这里哪个术语更好?)(否则a不是整数),并且q必须大于p(以获得正数a) - 这个事实允许更早地停止循环。

K=6 的示例:

2K = 12
1 * 12 :  n = 1, a = 6   (range 6..6)
2 * 6:   no solution (both even) 
3 * 4:    n = 3, a = 1  (range 1..3)
Run Code Online (Sandbox Code Playgroud)

简单的实现(对于非常大的值,它比@hilberts_drinking_problem 实现慢一点(两倍))

def findranges(k):
    n = 1
    kk = 2 * k
    res = []
    while n * n < kk:
        if kk % n == 0:
            q = kk // n
            if (q ^ n) & 1: //compare parity using the least significant bit
                a = (q + 1 - n) // 2
                res.append([a, a + n - 1])
        n += 1
    return res

print(findranges(60))

  
Run Code Online (Sandbox Code Playgroud)