[路飞]_279.完全平方数

185 阅读2分钟

「这是我参与2022首次更文挑战的第19天,活动详情查看:2022首次更文挑战

279. 完全平方数

题目

给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。

完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。

示例1

输入: n = 12
输出: 3 
解释: 12 = 4 + 4 + 4

示例2

输入: n = 13
输出: 2
解释: 13 = 4 + 9

题解

动态规划

分析数据:

  • n=0n = 0 可以分解为 0;需要 11 个完全平方数
  • n=1n = 1 可以分解为 1;需要 11 个完全平方数
  • n=2n = 2 可以分解为 1+11 + 1;需要 22 个完全平方数
  • n=3n = 3 可以分解为 1+22+11+2、2+1;
    • 解释一下,33可以分解为1+21+222 之前计算过,可以分解为1+11+1;所以3=1+1+13 = 1+1+1,需要 33 个完全平方数
  • n=4n = 4 可以分解为 1+32+23+14+01+3 、2+2、3+1、4+0;
    • 解释一下,4可以分解为1+3,3之前计算过,3可以分解为1+1+11+1+1;所以 4=1+1+1+14 = 1+1+1+1
    • 44可以分解为2+22+222可以分级为1+11+1,所以 4=1+1+1+14 = 1+1+1+1
    • 44可以分解为3+1,与1+3同理
    • 44可以分解为4+0;所以 4=44 = 4 需要 11 个完全平方数
    • 取这几种可能使用最少完全平方数的作为 44 的答案
  • ...
  • n=12n = 12 可以分解为 1+11,2+10,3+9,...,11+11+11,2+10,3+9,...,11+1; 都是之前计算过的,可以从之前计算结果获取找到最小值即完成

根基上述思路完成代码如下

代码

var numSquares = function (n) {
  const list = [0, 1]
  for (let i = 2; i <= n; i++) {
    let min = Infinity
    for (let j = 1; j * j <= i; j++) {
      min = Math.min(min, list[i - j * j] + 1)
    }
    list[i] = min
  }

  return list[n]
}

纯数学方法

一个重要概念四平方和定理

四平方和定理证明了任意一个正整数都可以被表示为至多四个正整数的平方和。

  • n=4k×(8m+7)n=4k×(8m+7), nn 一定是由四个完全平方数组成
  • nn 开方求余为0, nn 表示某个数的平方数,所以 nn 是由一个完全平方数组成
  • 如果是两个完全平方数组成,n=a2+b2n = a^2 + b^2
  • 如果都不是,nn 只能被三个完全平方数组成

根基上述思路完成代码如下

代码

var numSquares = function (n) {
  let temp = n
  while (temp % 4 === 0) {
    temp = Math.floor(temp / 4)
  }
  if (temp % 8 === 7) return 4
  const s = Math.sqrt(n, 2)
  if (s % 1 === 0) return 1
  let index = 0
  while (index * index < n) {
    const a = index * index
    const bb = n - a
    b = Math.sqrt(bb, 2)
    if (b % 1 === 0) return 2
    index++
  }
  return 3
}