二面是一个印度人,长的有一点小帅。穿的就是程序员最经常的格子衫,明显感觉是个严肃的人。一上来就问了彼此好,然后就有点尴尬,谁也没说话。很有和一个不认识的人做CS Project的尴尬的感觉。很快,他就直入主题了,首先问了我一个System Design的问题,问如果我要设计一个新的交友软件的话,需要哪些元素,和哪些Function。幸好之前简历课上也被老师问过同样的问题。其实我第一次听到的时候还挺蒙圈的,没想到其实我们习以为常的这些东西背后需要很多的思考。
![53998f9099806c3172dee2c240700193.png](https://i-blog.csdnimg.cn/blog_migrate/67cc198ec9339e65f4d5a8bf10d33fd7.jpeg)
简历课上被问过无数遍,按照Justin老师交给我的,我先问了一下需要设计到什么程度,需要哪些功能,然后根据功能设计了元素和function。面试官看着也挺满意的。
![f1867edf1c8d7fa2c3f5090aa937a1b8.png](https://i-blog.csdnimg.cn/blog_migrate/83a8d3e3e88948a0a6d20d62df41d04b.jpeg)
然后就是面试题:
题目
01
Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, ...) which sum to n. For example, given n = 12, return 3 because 12 = 4 + 4 + 4; given n = 13, return 2 because 13 = 4 + 9.
给出一个正整数n,求至少需要多少个完全平方数(例如1,4,9,16……)相加能得到n。例如,给出n = 12,返回3,因为12 = 4 + 4 + 4。给出n = 13,返回2,因为13 = 4 + 9。
![3fbc87f3c82c7fb5e5cb66d5ac7fcc09.png](https://i-blog.csdnimg.cn/blog_migrate/efc106a5a59694a805093ba3ba7cf031.png)
分析
01
乍一看题目,比较天真的想法是,先从不大于n的最大的完全平方数开始组合,如果和超过了n,就换小一点的完全平方数。但问题是,最后如果凑不齐的话,只能添加很多1,总量上就不是最少的了。例如12,题目中给的例子是4+4+4,需要3个完全平方数。如果从最大的开始组合,那么是9+1+1+1,需要4个完全平方数。
![46d94d5b9b9f6b202f510f08cce584ad.png](https://i-blog.csdnimg.cn/blog_migrate/1115458b2cc915658edeb58d5ad56a36.png)
从另一个角度来想,用穷举法来求解就是把不大于n的所有可能的完全平方数的组合都算出来,然后找出和为n的组合中数量最少的那种组合。如果不大于n的完全平方数有m个的话,这个方法的时间复杂度是O(m^m)。显然穷举法时间复杂度过大,不是可行的方法。观察到,在枚举的过程中,有一些组合显然不是最优的,比如把12拆成12个1相加。另外,如果我们能够记录已经找到的最小组合,那么稍大一些的数只需要在此基础上添加若干个完全平方数即可。这里面就包含了动态规划的思想。
![46d94d5b9b9f6b202f510f08cce584ad.png](https://i-blog.csdnimg.cn/blog_migrate/1115458b2cc915658edeb58d5ad56a36.png)
具体来说,我们用一个数组来记录已有的结果,初始化为正无穷(INT_MAX)。外层循环变量i从0到n,内层循环变量j在i的基础上依次加上每个整数的完全平方,超过n的不算。那么i + j*j这个数需要的最少的完全平方数的数量,就是数组中当前的数值,和i位置的数值加上一,这两者之间较小的数字。如果当前的值较小,说明我们已经找到过它需要的完全平方数的个数(最初都是正无穷)。否则的话,说明在i的基础上加上j的平方符合条件,所需的完全平方数的个数就是i需要的个数加上一。
![6ad33ea865db387913f990fbf800b116.png](https://i-blog.csdnimg.cn/blog_migrate/8e19acfd4d7837c5b3794b946b556a97.png)
代码
01
1class Solution {
2public:
3int numSquares(int n) {
4 vector<int> dp(n + 1, INT_MAX);
5 dp[0] = 0;
6 for (int i = 0; i <= n; i++) {
7 for (int j = 1; i + j * j <= n; j++) {
8 dp[i + j * j] = min(dp[i + j * j], dp[i] + 1);
9 }
10 }
11 return dp[n];
12}
13};
万万没想到,这道题我在Justin导师的算法课上见过。题目不难,但还是需要一定的数学。不愧是Justin导师算法DP课上强调的重点,没想到真的在面试中遇到了。我立刻按照原来的方法记录之前的值,然后用现有的组合得出更大的值。面试官都说我做的很快,而且代码一次正确。
面试结束后,我赶紧感谢了Justin导师,没想到这已经不是偶然操作了。
![bb9f4ed6dc15e54dc69361d39c7edb84.png](https://i-blog.csdnimg.cn/blog_migrate/1a7fbfb211259739d0cf429f78a423eb.png)
三面欢迎关注之后的公众号内容~
第四期算法训练营马上开始啦,现在开放报名,导师都是在职的Tech Lead和部门的面试出题人,不仅可以接触到微软内部题库,还有七句心决可以让你制霸一切算法题~同学可以加微信领取10%的优惠券哦!还没有进群的小伙伴们抓紧了~
![0f141e24e87639ae73fb233581c28266.png](https://i-blog.csdnimg.cn/blog_migrate/ac8faebee92c5601c04e90bf519ea9f2.jpeg)
![277f564358b839f60de030b3a1c78a29.png](https://i-blog.csdnimg.cn/blog_migrate/9038fceae1a8dece277ebf1d11fae528.png)
![9e463d323b83ca11a647ec884875fe79.png](https://i-blog.csdnimg.cn/blog_migrate/183344c60cd847bbfc85fc2e09f47710.jpeg)