Leetcode的完美广场

Perfect Square in Leetcode

本文关键字:完美 Leetcode      更新时间:2023-10-16

我很难理解Leetcode问题。

给定一个正整数n,求和为n的完美平方数的最小数(例如,1、4、9、16…(。

例如,给定n=12,返回3,因为12=4+4+4;给定n=13,则返回2,因为13=4+9。

解决方案:

int numSquares(int n) {
    static vector<int> dp {0};
    while (dp.size() <= n) {
        int m = dp.size(), squares = INT_MAX;
        for (int i=1; i*i<=m; ++i)
            squares = min(squares, dp[m-i*i] + 1);
        dp.push_back(squares);
    }
    return dp[n];
}

我真的不明白min(squares,dp[m-i*i]+1)是怎么回事。你能解释一下吗?

thx。

我也遇到了困难。让我们举一个n=13的例子。

  • 首先要观察的是:1^2=1,2^2=4,3^2=9,4^2=16
    • 所以13不可能由大于3^2。一般来说,n只能由数字1到sqrt(n(组成
    • 因此,我们只剩下以下数字的平方的组合:1、2或3
  • 接下来我们要做的是提出递归公式。我花了很长时间才明白。但我们基本上想缩小到使用较小的n(这就是递归的全部意义(。我们通过从n中减去我们的候选完美平方来做到这一点。例如:
    • 如果我们尝试3,那么dp(13(=dp(13-3^2(+1=dp(4(+1。+1是将计数增加1,这是因为我们已经从13减去了一个完美的正方形,也就是3^2。每个+1都是一个完美的正方形
    • 如果我们尝试2,那么dp(13(=13-2^2=dp(9(+1
    • 如果我们尝试1,那么dp(13(=13-1^2=dp(12(+1

因此,我们只需要比较dp(4(、dp(9(和dp(12(中哪一个最小。因此,最小

您提到的解决方案是自下而上版本的算法。为了更好地理解算法,我建议查看自上而下的解决方案。

让我们更仔细地研究包含在数字N中的完美平方的最小数量的计算的递推关系。对于给定的N和任意数x(它是被认为是最短数列成员的候选者,其平方和为N(:

f(N, x) = 0                                 , if N = 0    ;
f(N, x) = min( f(N, x + 1), f(N - x^2, 1) ) , if N >= x^2 ;
f(N, x) = +infinity                         , otherwise   ;
solution(N) = f(N, 1)

现在,考虑到所考虑的递归,我们可以构建自上而下的解决方案(我将在Java中实现它(:

int solve(int n) {
    return solve(n, 1);
}
int solve(int n, int curr) {
    if (n == 0) {
        return 0;
    }
    if ((curr * curr) > n) {
        return POSITIVE_INFINITY;
    }
    // if curr belongs to the shortest sequence of numbers, whose perfect squares sums-up to N
    int inclusive = solve(n - (curr * curr), 1) + 1;
    // otherwise:
    int exclusive = solve(n, curr + 1);
    return Math.min(exclusive, inclusive);
}

给定解决方案的运行时复杂性是指数级的。

然而,我们可以注意到,n[1..n]可能值和curr[1..sqrt(n)]可能值。这意味着函数solve的自变量的不同值只有n * sqrt(n)的组合。因此,我们可以创建记忆表,并降低自上而下解决方案的复杂性:

int solve(int n) {
    // initialization of the memoization table
    int[][] memoized = new int[n + 1][(int) (Math.sqrt(n) + 1)];
    for (int[] row : memoized) {
        Arrays.fill(row, NOT_INITIALIZED);
    }
    return solve(n, 1, memoized);
}
int solve(int n, int curr, int[][] memoized) {
    if (n == 0) {
        return 0;
    }
    if ((curr * curr) > n) {
        return POSITIVE_INFINITY;
    }
    if (memoized[n][curr] != NOT_INITIALIZED) {
        // the sub-problem has been already solved
        return memoized[n][curr];
    }
    int exclusive = solve(n, curr + 1, memoized);
    int inclusive = solve(n - (curr * curr), 1, memoized) + 1;
    memoized[n][curr] = Math.min(exclusive, inclusive);
    return memoized[n][curr];
}

给定的解决方案具有运行时复杂性O(N * sqrt(N))

然而,可以将运行时复杂性降低到O(N)

f(N, x)的递推关系仅依赖于f(N, x + 1)f(N - x^2, 1)而言,这意味着该关系可以等价地转换为循环形式:

f(0) = 0
f(N) = min( f(N - x^2) + 1 ) , across the all x, such that x^2 <= N

在这种情况下,我们必须仅为其参数的N的不同值存储f(N)。因此,下面介绍了O(N)自上而下的解决方案:

int solve_top_down_2(int n) {
    int[] memoized = new int[n + 1];
    Arrays.fill(memoized, NOT_INITIALIZED);
    return solve_top_down_2(n, memoized);
}
int solve_top_down_2(int n, int[] memoized) {
    if (n == 0) {
        return 0;
    }
    if (memoized[n] != NOT_INITIALIZED) {
        return memoized[n];
    }
    // if 1 belongs to the shortest sequence of numbers, whose perfect squares sums-up to N
    int result = solve_top_down_2(n - (1 * 1)) + 1;
    for (int curr = 2; (curr * curr) <= n; curr++) {
        // check, whether some other number belongs to the shortest sequence of numbers, whose perfect squares sums-up to N
        result = Math.min(result, solve_top_down_2(n - (curr * curr)) + 1);
    }
    memoized[n] = result;
    return result;
}

最后,所提出的自上而下的解决方案可以很容易地转换为自下而上的解决方案:

int solve_bottom_up(int n) {
    int[] memoized = new int[n + 1];
    for (int i = 1; i <= n; i++) {
        memoized[i] = memoized[i - (1 * 1)] + 1;
        for (int curr = 2; (curr * curr) <= i; curr++) {
            memoized[i] = Math.min(memoized[i], memoized[i - (curr * curr)] + 1);
        }
    }
    return memoized[n];
}

澄清您的困惑在于问题本身。结构CCD_ 20保持最小平方数,其总和为CCD_ 21的索引位置。

例如,squares将在n=9时返回3,但最不可能的是1,这是dp[m- i*i] + 1将返回的。