Perfect Squares

题目来源 leetcode 279

给定一个整数n,n可以分解为m个平方数的和,求m的最小值。平方数可以重复,例如12可以分解为4+4+4。

这个问题用动态规划比较好求解。如果对背包问题比较熟悉,最容易想到的方法就是将平方数看成数类物体,将这些物体组合(可重复),构成n的最小物体数就是答案。用dp[n]表示构成n的平方数的最小数目。则dp[n]=min(dp[n-k*i*i]+dp[k*i*i]),其中k*i*i小于等于n。但是,对于比较大的n,这个算法的效率就很低了。

现在深入思考一点。在得知dp[0]到dp[n-1]的情况下,有必要计算dp[n-k*i*i](k>=2)这样的情况吗?并不需要,因为将n拆成k个平方数a1和另一个数a2,再讨论最小平方数数目,相当于将n拆为一共平方数a1,和另一个数a3=a2+(k-1)*a1,并且在分解a3时运用不一定是最佳的分解方式,在这种情况下,结果一定不会比分解a3时用最佳分解方式更好,也就是说当k>=2时,结果一定不会比k=1时更好。举个例子,对于dp[10],dp[10-1*1]+dp[1*1]是一定比dp[10-2*1*1]+dp[2*1*1]更小的,因为dp[9]<=dp[8]+dp[1]<dp[8]+dp[2]。由此可以得到状态转移方程dp[n]=min(dp[n-i*i]+1)。状态数为n,处理每个状态时间为n^0.5,总时间复杂度为n^1.5。


int numSquares(int n) {
	const int INF = 10000000;
	vector<int> sq;
	for (int i = 1; i*i <= n; i++)
	{
		sq.push_back(i*i);
	}
	vector<int> dp(n + 1, INF);
	dp[0] = 0;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j<sq.size()&&sq[j]<=i; j++)
		{
			if (dp[i] > dp[i - sq[j]] + 1)
				dp[i] = dp[i - sq[j]] + 1;
		}
	}
	return dp[n];
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值