LeetCode 279. Perfect Squares


Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, ...) which sum to n.

For example, given n = 12, return 3 because 12 = 4 + 4 + 4; given n = 13, return 2 because 13 = 4 + 9.


【題目分析】

一個數可以由一些完全平方數相加得到,例如1,4,9,16,...

給定一個數n,求出使得相加結果為n所需最少的完全平方數的個數。


【思路】

1. 遞歸

  對於一個數,我們怎么求它的由哪些完全平方數相加得到的呢?

  首先找到距離這個數最近的完全平方數m = x*x,我們從1~x中選擇一個數,求出n中包含z個x*x,我們在遞歸求出n-z*x*x所包含的完全平方數。遍歷1~x,返回其中最小的結果。

2. 動態規划

  動態規划用 dp[i] 數組存儲第 i 個數的完美平方數。遞推式為:dp[i] = Math.min(dp[j] + dp[i-j], dp[i]),認為 i 的完全平方數是從和為 i 的兩個完全平方數 dp[j] 和 dp[i-j]之和,然后從中取最小。

 3. 改進后的動態規划

  

  如圖所示,紅色部分表示平方數,所有的數都可以看做一個普通數加上一個完美平方數,那么遞推式就變為了:dp[i + j * j] = Math.min(dp[i] + 1, dp[i + j * j])。


【java遞歸實現】

 1 public class Solution {
 2     public int numSquares(int n) {
 3         int count = n;
 4         int nearest = (int)Math.sqrt(n);
 5         if(n == 0) return 0;
 6         if(nearest*nearest == n) return 1;
 7         for(int i = nearest; i >= 1; i--) {
 8             int cur = 0, num  = n, t = i*i;
 9             while(num - t >= 0) {
10                 num -= t;
11                 cur++;
12             }
13             if(cur < count){
14                 count = Math.min(numSquares(num)+cur, count);
15             }
16         }
17         
18         return count;
19     }
20 }

時間606ms

 

【java實現動態規划】

 1 public class Solution {
 2     /*
 3     動態規划的思想來解決,遞推公式dp[i] = Math.min(dp[j] + dp[i-j], dp[i])
 4     */
 5     public int numSquares(int n) {
 6         int[] array = new int[n+1];
 7         Arrays.fill(array, Integer.MAX_VALUE);
 8         array[1] = 1;
 9         
10         for(int i = 2; i <=n; i++) {
11             int sqr = (int)Math.sqrt(i);
12             if(sqr*sqr == i) array[i] = 1;
13             else{
14                 for(int j = 1; j <= i/2; j++) {
15                     array[i] = Math.min(array[j]+array[i-j], array[i]);
16                 }
17             }
18         }
19         return array[n];
20     }
21 }

時間:1112ms

 【java實現改進后的動態規划】

 1 public class Solution {
 2     /*
 3     改進后動態規划,遞推公式dp[i+j*j] = Math.min(dp[i]+1, dp[i+j*j])
 4     */
 5     public int numSquares(int n) {
 6         int[] array = new int[n+1];
 7         Arrays.fill(array, Integer.MAX_VALUE);
 8         
 9         for(int i = 1; i*i <= n; i++) {
10             array[i*i] = 1;
11         }
12         for(int i = 1; i <= n; i++) {
13             for(int j = 1; i+j*j <= n; j++) {
14                 array[i+j*j] = Math.min(array[i]+1, array[i+j*j]);
15             }
16         }
17         return array[n];
18     }
19 }

時間:60ms

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM