279.perfect-squares.md 2.8 KB
Newer Older
L
luzhipeng 已提交
1
## 题目地址
L
luzhipeng 已提交
2

L
luzhipeng 已提交
3 4 5 6 7 8 9 10 11 12
https://leetcode.com/problems/perfect-squares/description/

## 题目描述

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

Example 1:

Input: n = 12
L
luzhipeng 已提交
13
Output: 3
L
luzhipeng 已提交
14 15 16 17 18 19 20 21 22 23 24 25
Explanation: 12 = 4 + 4 + 4.
Example 2:

Input: n = 13
Output: 2
Explanation: 13 = 4 + 9.

```

## 思路

直接递归处理即可,但是这种暴力的解法很容易超时。如果你把递归的过程化成一棵树的话(其实就是递归树),
L
luzhipeng 已提交
26
可以看出中间有很多重复的计算。
L
luzhipeng 已提交
27 28 29 30 31

如果能将重复的计算缓存下来,说不定能够解决时间复杂度太高的问题。

> 递归对内存的要求也很高, 如果数字非常大,也会面临爆栈的风险,将递归转化为循环可以解决。

L
luzhipeng 已提交
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
递归 + 缓存的方式代码如下:

```js
const mapper = {};

function d(n, level) {
  if (n === 0) return level;

  let i = 1;
  const arr = [];

  while (n - i * i >= 0) {
    const hit = mapper[n - i * i];
    if (hit) {
      arr.push(hit + level);
    } else {
      const depth = d(n - i * i, level + 1) - level;
      mapper[n - i * i] = depth;
      arr.push(depth + level);
    }
    i++;
  }

  return Math.min(...arr);
}
/**
 * @param {number} n
 * @return {number}
 */
var numSquares = function(n) {
  return d(n, 0);
};
```

如果使用 DP,其实本质上和递归 + 缓存 差不多。

DP 的代码见代码区。
L
luzhipeng 已提交
69 70 71 72

## 关键点解析

- 如果用递归 + 缓存, 缓存的设计很重要
L
luzhipeng 已提交
73 74 75
  我的做法是 key 就是 n,value 是以 n 为起点,到达底端的深度。
  下次取出缓存的时候用当前的 level + 存的深度 就是我们想要的 level.

L
luzhipeng 已提交
76
- 使用动态规划的核心点还是选和不选的问题
L
luzhipeng 已提交
77 78 79 80

```js
for (let i = 1; i <= n; i++) {
  for (let j = 1; j * j <= i; j++) {
L
luzhipeng 已提交
81
    // 不选(dp[i]) 还是  选(dp[i - j * j])
L
luzhipeng 已提交
82 83 84 85
    dp[i] = Math.min(dp[i], dp[i - j * j] + 1);
  }
}
```
L
luzhipeng 已提交
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124

## 代码

```js
/*
 * @lc app=leetcode id=279 lang=javascript
 *
 * [279] Perfect Squares
 *
 * https://leetcode.com/problems/perfect-squares/description/
 *
 * algorithms
 * Medium (40.98%)
 * Total Accepted:    168.2K
 * Total Submissions: 408.5K
 * Testcase Example:  '12'
 *
 * Given a positive integer n, find the least number of perfect square numbers
 * (for example, 1, 4, 9, 16, ...) which sum to n.
 *
 * Example 1:
 *
 *
 * Input: n = 12
 * Output: 3
 * Explanation: 12 = 4 + 4 + 4.
 *
 * Example 2:
 *
 *
 * Input: n = 13
 * Output: 2
 * Explanation: 13 = 4 + 9.
 */
/**
 * @param {number} n
 * @return {number}
 */
var numSquares = function(n) {
L
luzhipeng 已提交
125 126 127 128 129 130 131 132
  if (n <= 0) {
    return 0;
  }

  const dp = Array(n + 1).fill(Number.MAX_VALUE);
  dp[0] = 0;
  for (let i = 1; i <= n; i++) {
    for (let j = 1; j * j <= i; j++) {
L
luzhipeng 已提交
133
      // 不选(dp[i]) 还是  选(dp[i - j * j])
L
luzhipeng 已提交
134 135 136 137 138
      dp[i] = Math.min(dp[i], dp[i - j * j] + 1);
    }
  }

  return dp[n];
L
luzhipeng 已提交
139 140
};
```