leetcode 279. 徹底平方數 -- javascript dp

279. 徹底平方數

題目描述

給定正整數 n,找到若干個徹底平方數(好比 1, 4, 9, 16, ...)使得它們的和等於 n。你須要讓組成和的徹底平方數的個數最少。算法

給你一個整數 n ,返回和爲 n 的徹底平方數的 最少數量 。markdown

徹底平方數 是一個整數,其值等於另外一個整數的平方;換句話說,其值等於一個整數自乘的積。例如,一、四、9 和 16 都是徹底平方數,而 3 和 11 不是。oop

image.png

題解

動態規劃(Dynamic Programming, DP)

  • 動態規劃只能應用於有最優 子結構的問題。最優子結構的意思是局部最優解能決定全局最優解(對有些問題這個要求並不能徹底知足,故有時須要引入必定的近似)。spa

  • 簡單地說,問題可以分解成子問題來解決code

  • 通俗一點來說,動態規劃和其它遍歷算法(如深/廣度優先搜索)都是將原問題拆成多個子問題而後求解,他們之間最本質的區別是,動態規劃保存子問題的解,避免重複計算orm

  • 解決動態規劃問題的關鍵是找到狀態轉移方程,這樣咱們能夠通計算和儲存子問題的解來求解最終問題leetcode

  • 同時,咱們也能夠對動態規劃進行空間壓縮,起到節省空間消耗的效果。get

  • 在一些狀況下,動態規劃能夠當作是帶有狀態記錄(memoization)的優先搜索it

  • 動態規劃是自下而上的,即先解決子問題,再解決父問題;io

  • 而用帶有狀態記錄的優先搜索自上而下的,即從父問題搜索到子問題,若重複搜索到同一個子問題則進行狀態記錄,防止重複計算。

  • 若是題目需求的是最終狀態,那麼使用動態搜索比較方便;

  • 若是題目須要輸出全部的路徑,那麼使用帶有狀態記錄的優先搜索會比較方便。

回到本題目

咱們定義一個一維矩陣 dp,其中 dp[i] 表示數字 i 最少能夠由幾個徹底平方數相加構成。
枚舉到k的時候,看k^2 算一個數dp[i] = 1, 加上剩下的i-k^2 計算還有多少的平方數 而且 包含的數目要求最小。

所以 dp[i] 能夠取的最小值即爲 1 + min(dp[i-1], dp[i-4], dp[i-9]...);

狀態轉移方程

image.png
由於計算 f[i] 時所須要用到的狀態僅有 f[i-j^2] ,必然小於i,所以咱們只須要從小到大地枚舉 i 來計算 f[i]便可。

coding

/**
 * @param {number} n
 * @return {number}
 */
var numSquares = function(n) {
    let dp = new Array(n+1).fill(0);
    for(let i = 1; i <= n; i ++) {
        dp[i] = Number.MAX_SAFE_INTEGER;
        for(let j = 1; j*j <= i; j++) {
            dp[i] = Math.min(dp[i], dp[i- j*j] + 1);
        }
    }
    return dp[n];
};
複製代碼
相關文章
相關標籤/搜索