【问题标题】:Sum of all possible distinct perfect squares equals to square of given number所有可能的不同完全平方的总和等于给定数的平方
【发布时间】:2017-08-18 19:35:38
【问题描述】:

我正在尝试编写一个程序来解决如下所述的问题 “打印所有可能的不同完美平方,其总和等于给定数字的平方”。 比如——

输入

11

输出

1 4 16 36 64

1 4 16 100

4 36 81

我尝试了基本的递归方法,并且我的代码通过了少量输入。当我尝试像 116 这样的更大数字时,它会永远运行。我的JAVA代码

public class SumOfPerfectSquare {
    public static void main(String args[]){
        generateSum(11);
    }

    private static void generateSum(int num) {
        int arr[] = new int[num];
        for(int i=1; i<num; i++){
            arr[i] = i*i;
        }
        findSum(arr, num*num, 1, 0, "");
    }

    private static void findSum(int arr[], int desiredSqr, int pointer, int currentSum, String sumStr) {
        if(pointer == arr.length || currentSum >= desiredSqr){
            if(currentSum == desiredSqr){
                System.out.println(sumStr);
            }
            return;
        }
        for(int i=pointer; i<arr.length; i++){
            findSum(arr, desiredSqr, i+1, currentSum+arr[i], sumStr+arr[i]+" ");
        }
    }
}

请告诉我是否有更好的方法来解决这个问题(时间复杂度更低)

【问题讨论】:

  • 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 呢?
  • Nopes 需要不同的完美正方形。我已经编辑了问题以使其清楚
  • 好的,你知道116有多少种解决方案吗?
  • 你需要使用memoization
  • @AaditMShah memoisation 到底有什么帮助?请注意,总和的所有组成部分都必须是不同的。

标签: algorithm math recursion perfect-square


【解决方案1】:

这可以在 O(n*sqrt(n)) 中完成,方法是将其转换为 subset sum problem。如何?

考虑所有小于或等于 N 的完全正方形。此类元素的数量为 sqrt(N)。

现在的问题是我们有多少种方法可以选择这些元素的子集,使得总和 = N

这里是关于这个问题的discussion,你可以在这里找到similar questions

如果通过动态规划解决问题的复杂性将是 O(n*sqrt(n))

打印所有这些组合将具有 O(sqrt(n)*2^(sqrt(n))) 复杂性,因为它们可能是 2^(sqrt(n)) 个子集。我们必须检查这个子集是否有 sum = N。

现在如果我们遍历从 1 到 2^(srtn(N)-1) 的所有数字。这个数字可以表示所有子集,这些子集将是这个数字的集合位的索引。遍历这个数字需要 O(sqrt(N)) 时间。

所以总体复杂度 O(sqrt(N) * 2^(sqrt(N)))。

【讨论】:

  • OP 想要打印所有的方式,而不是计算它们。
【解决方案2】:

Memoization 当然有助于降低这个问题的时间复杂度:

const memoize = callback => {
    const memo = new Map;

    return function () {
        const length = arguments.length, last = length - 1;

        let map = memo;

        for (let i = 0; i < last; i++) {
            const argument = arguments[i];
            if (!map.has(argument)) map.set(argument, new Map);
            map = map.get(argument);
        }

        const argument = arguments[last];
        if (!map.has(argument)) map.set(argument, callback.apply(null, arguments));
        return map.get(argument);
    };
};

const generateSums = memoize((sum, xs, index) => {
    if (sum === 0) return [[]];

    const result = [], length = xs.length;

    for (let i = index; i < length; i++) {
        const x = xs[i], diff = sum - x;
        let j = i + 1; while (xs[j] > diff) j++;
        const xss = generateSums(diff, xs, j);
        for (const xs of xss) result.push([x].concat(xs));
    }

    return result;
});

const solve = n => {
    const xs = [];
    for (let x = n - 1; x > 0; x--) xs.push(x * x);
    return generateSums(n * n, xs, 0);
};

console.time("Generate sums for 50²");
console.log(solve(50).length);
console.timeEnd("Generate sums for 50²");

如果没有记忆,它需要更长的时间(请注意,它可能会导致您的浏览器崩溃):

const generateSums = (sum, xs, index) => {
    if (sum === 0) return [[]];

    const result = [], length = xs.length;

    for (let i = index; i < length; i++) {
        const x = xs[i], diff = sum - x;
        let j = i + 1; while (xs[j] > diff) j++;
        const xss = generateSums(diff, xs, j);
        for (const xs of xss) result.push([x].concat(xs));
    }

    return result;
};

const solve = n => {
    const xs = [];
    for (let x = n - 1; x > 0; x--) xs.push(x * x);
    return generateSums(n * n, xs, 0);
};

console.time("Generate sums for 50²");
console.log(solve(50).length);
console.timeEnd("Generate sums for 50²");

解决 116 平方仍然需要太多时间,但这是一个开始。

【讨论】:

  • 有 67142554778 种不同的方式将 116^2 表示为不同平方的总和。祝你今天把它们全部打印出来。
  • 嗨@n.m 你是如何找到将 116^2 表示为不同平方和的方法的数量?
  • @Anakar Parida oeis 是你的朋友oeis.org/A030273/b030273.txt
  • @n.m 太不可思议了。谢谢,但有没有可能通过计算找到它。一种从数学上解决这个问题的程序
  • 分解成不同方块的 数量 很容易计算。序列页面oeis.org/A030273 有一个 Haskell 和 Mathematica 程序
猜你喜欢
  • 2020-09-11
  • 1970-01-01
  • 2011-06-07
  • 1970-01-01
  • 2011-11-11
  • 1970-01-01
  • 1970-01-01
  • 2017-12-23
  • 1970-01-01
相关资源
最近更新 更多