【问题标题】:How to tell if number can be writen as sum of n different squares?如何判断数字是否可以写为 n 个不同平方的总和?
【发布时间】:2021-11-18 19:05:18
【问题描述】:

我知道如何使用蛮力方法检查数字是否可以表示为两个平方和。

def sumSquare( n) :
    i = 1
    while i * i <= n :
        j = 1
        while(j * j <= n) :
            if (i * i + j * j == n) :
                print(i, "^2 + ", j , "^2" )
                return True
            j = j + 1
        i = i + 1

    return False

但是如何为 n 个不同的正整数做到这一点。所以问题是:

检查数字是否可以写为“n”个不同平方之和的函数

我有一些例子。

例如

  1. is_sum_of_squares(18, 2) 将是错误的,因为 18 可以写成两个平方的和 (3^2 + 3^2),但它们并不不同。
  2. (38,3) 为真,因为 5^2+3^2+2^2 = 38 和 5!=3!=2。

我无法扩展if 条件以获得更多值。我认为这可以通过递归来完成,但我有问题。

我发现这个函数非常有用,因为它可以找到数字可以分割成的平方数。

def findMinSquares(n):
    T = [0] * (n + 1)
    for i in range(n + 1):
        T[i] = i
        j = 1
        while j * j <= i:
            T[i] = min(T[i], 1 + T[i - j * j])
            j += 1

    return T[n]

但我又不能用递归来做到这一点。可悲的是,我无法绕过它。我们几周前开始学习它(我在高中),它与迭代方法有很大不同。

【问题讨论】:

    标签: python recursion math


    【解决方案1】:

    递归方法:

    def is_sum_of_squares(x, n, used=None):
        x_sqrt = int(x**0.5)
        if n == 1:
            if x_sqrt**2 == x:
                return used.union([x_sqrt])
            return None
        used = used or set()
        for i in set(range(max(used, default=0)+1, int((x/n)**0.5))):
            squares = is_sum_of_squares(x-i**2, n-1, used.union([i]))
            if squares:
                return squares
        return None
    

    【讨论】:

    • 好的,这可以找到列表中的所有方块,对吗?如果它找不到足够的,它会返回 None。但是对于例如对于输入 is_sum_of_squares(100,3) 这应该是 None (False) 它返回 [8,6,0] 这被认为是 True。这是为什么呢?
    • 我把问题指定错了。您的函数检查它是否可以小于或等于 N 个平方,对吗?而不是 N?
    • @TomášKrál 这是一个错误。我更新了答案来解决这个问题
    • 是的,它似乎正在做我需要的事情。所以我会去调试它并尝试理解它:D 非常感谢
    • @TomášKrál 立即尝试。如果我们仅按递增顺序考虑正方形,则会消除许多相同的组合,仅按顺序不同(n! 复杂性降低)。 (1000, 13) 示例现在大约需要一秒钟
    【解决方案2】:

    相当引人注目的练习。我尝试以回溯的形式使用递归来解决它。从一个空列表开始,运行一个 for 循环来添加从 1 到最大可行(目标数的平方根)的数字,并为每个添加的数字继续递归。一旦列表达到所需的大小 n,验证结果。如果结果不正确,则通过删除最后一个数字来回溯。 但不确定它是否 100% 正确。在速度方面,我在 (1000,13) 输入上进行了尝试,并且过程相当快(3-4s)完成。

    def is_sum_of_squares(num, count):
        max_num = int(num ** 0.5)
        return backtrack([], num, max_num, count)
    
    
    def backtrack(candidates, target, max_num, count):
        """
        candidates = list of ints of max length <count>
        target = sum of squares of <count> nonidentical numbers
        max_num =  square root of target, rounded
        count = desired size of candidates list
        """
        result_num = sum([x * x for x in candidates])  # calculate sum of squares
        if result_num > target:  # if sum exceeded target number stop recursion
            return False
        if len(candidates) == count:  # if candidates reach desired length, check if result is valid and return result
            result = result_num == target
            if result:  # print for result sense check, can be removed
                print("Found: ", candidates)
            return result
        for i in range(1, max_num + 1):  # cycle from 1 to max feasible number
            if candidates and i <= candidates[-1]:
                # for non empty list, skip numbers smaller than the last number.
                # allow only ascending order to eliminate duplicates
                continue
            candidates.append(i)  # add number to list
            if backtrack(candidates, target, max_num, count):  # next recursion
                return True
            candidates.pop()  # if combination was not valid then backtrack and remove the last number
        return False
    
    
    assert(is_sum_of_squares(38, 3))
    assert(is_sum_of_squares(30, 3))
    assert(is_sum_of_squares(30, 4))
    assert(is_sum_of_squares(36, 1))
    assert not(is_sum_of_squares(35, 1))
    assert not(is_sum_of_squares(18, 2))
    assert not(is_sum_of_squares(1000, 13))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-25
      • 1970-01-01
      • 2011-05-31
      • 2013-09-29
      • 1970-01-01
      • 1970-01-01
      • 2015-05-25
      • 1970-01-01
      相关资源
      最近更新 更多