Week14
Dynamic Programming
question source: 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.
question description
Example 1 :
Input: n = 12
Output: 3
Explanation: 12 = 4 + 4 + 4.
Example 2:
Input: n = 13
Output: 2
Explanation: 13 = 4 + 9
解决方法
题目是说判断一个数能最少用多少个平方数之和表示出来。这道题的标签是DP问题。本来想是否能用贪心算法表示出来,先将这个数分割成最大的平方数和另一个数,然后在另一个数中重复这个做法。但是很快就能看出一个反例。12 = 9 + 1 + 1 + 1需要4个,而最少其实是12 = 4 +4+4。然后就想用动态规划来解决了。
先定义子问题,num[i]定义为i这个数能最小多少个平方数之各和来表示。则问题的解为num[n]。
n
u
m
[
i
]
=
m
i
n
{
n
u
m
[
i
−
j
∗
j
]
+
1
,
i
>
=
j
∗
j
}
num[i] = min \{num[i - j * j] + 1, i >= j * j\}
num[i]=min{num[i−j∗j]+1,i>=j∗j}
然后定义开始值。要多一个额外的量num[0]为0, nums[1]为1。
class Solution {
public:
int numSquares(int n) {
int num[n + 1];
num[0] = 0;
num[1] = 1;
for(int i = 2; i <= n; i++){
int min = i;
for(int j = 2; j * j <= i; j++){
if(min > num[i - j * j] + 1){
min = num[i - j * j] + 1;
}
}
num[i] = min;
}
return num[n];
}
};
算法复杂度是 O ( n l o g n ) O(nlogn) O(nlogn)
这题的另一个标签为Math,所以是可以通过数学方法来解决了。有一个定理叫四平方和定理,每一个正整数均可表示4个整数的平方和。还有一个Legendre’s three-square theorem,是说一个自然数能被表示为三个平方之和当且仅当它不符合 n = 4 a ( 8 ∗ b + 7 ) n = 4^a(8 * b + 7) n=4a(8∗b+7),a和b是整数。因此可以用这些数学定理来解决。首先判断这个数是否是某个数的平方,如果是,则返回1。其次,再判断能否分为2个数之和,如果是,则返回2,再判断是否是否符合前面的表达式,如果是,则返回4,否则返回3。
class Solution {
public:
bool isSquare(int n){
int sqr = floor(sqrt(n));
return sqr * sqr == n;
}
int numSquares(int n) {
if(isSquare(n)){
return 1;
}
for(int i = 1; i * i < n; i++){
if(isSquare(n - i * i)){
return 2;
}
}
int a = 1;
while(n % (4 * a) == 0){
a *= 4;
}
if((n / a) % 8 == 7){
return 4;
}
return 3;
}
};
是真的快,数学真的厉害啊!果然很多搞计算机的人才数学都不差。这个算法复杂度是 O ( l o g n ) O(logn) O(logn)