LeetCode -- 279. Perfect Squares(完美平方)

6 篇文章 0 订阅
6 篇文章 0 订阅


一、原文

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.


二、翻译

给定一个正整数 n,找出累积和为 n 所需的最少完美平方数。


三、分析


3.1 BFS

此题如果不是在BFS这个tag里看到我肯定不会想到用BFS去求解,而是用DP。既然此题划分在了BFS这个tag中,那么此处就用BFS的思想去求解它。

首先,BFS是一个搜索算法,常用来求解树和图的问题,并且BFS有个特性非常重要:BFS能求最短路径问题(图的话要无权图,有权图使用图的其他最短路径算法)。此处不证明这个定理。

再者,此题从题面上看不出明显的树和图的结构,那么能用BFS吗?答案当然是肯定的,不然也不会划分在BFS这个tag中。

为什么可以使用BFS?因为每次都是从平方数中去一个个相加,再将结果判断之后加入队列,也就是说每次循环之后的结果就相当于树中的下一层就队列。

给定了n,那么就可以求出小于等于n的所有平方数,每次的加数也是从这些平方数中去寻找(注意,两个平方数相加的和可以成为一个被加数)。既然这样,肯定有个循环是用来循环平方数这个vector的(存储在vector中),并做为加数,每次从队列中出队的做被加数,和加数相加的和与n进行比较,如果大于则直接退出这个循环,小于则将此和标记一下(表示已经有过了,即访问过),等于的话就找到了,直接返回。

此处的结果是要求找出个数,BFS是按层来的,最后结果也就是遍历了多少层。

(好像有点混乱T_T,书面语言能力实在是弱,大家看代码吧)


3.2 DP

DP状态定义:dp[n],表示n所需的最少完美平方数。

DP状态转移方程:dp[n] = min{dp[n], dp[n - j * j] + 1}。


四、AC代码


4.1 BFS代码

int numSquares(int n) {
		if (n < 0) {
			return 0;
		}

		vector<int> perfect_square_numbers;
		vector<int> visited(n + 1);
		queue<int> q;
		for (int i = 1; i * i <= n; ++i) {
			perfect_square_numbers.push_back(i * i);
			visited[i * i] = 1;
			q.push(i * i);
		}
		if (n == q.back()) {
			return 1;
		}

		int ans = 1;
		while (!q.empty()) {
			++ans;
			int queue_size = q.size();
			for (int i = 0; i < queue_size; ++i) {
				int tmp = q.front();
				q.pop();
				for (int psn : perfect_square_numbers) {
					if (tmp + psn == n) {
						return ans;
					}
					if (tmp + psn > n) {
						break;
					}
					if (tmp + psn < n && visited[tmp + psn] == 0) {
						q.push(tmp + psn);
						visited[tmp + psn] = 1;
					}
				}
			}
		}

		return 0;
	}

4.2 DP代码

int numSquares(int n) {
		if (n < 0) {
			return 0;
		}

		vector<int> dp(n + 1, INT_MAX);
		dp[0] = 0;
		for (int i = 1; i <= n; ++i) {
			for (int j = 1; j * j <= i; ++j) {
				dp[i] = min(dp[i], dp[i - j * j] + 1);
			}
		}

		return dp[n];
	}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值