Leetcode[837]新21点&[825]适龄的朋友&[133]克隆图
在家果然效率低下,自学的第一天就只完成了一天任务的1/3,本来计划leetcode部分完成三道题并写一篇博客来着,然而并没有完成。
虽然主观原因是因为自己懒,但也有一定客观原因,837这道medium卡了我好久,可能是我数学太差了吧。
第一道题,新21点,首先我就没想到这道题可以用动态规划解,但有提示后可以联想到这题其实和背包问题有一定相似度
因为这题卡了我好久,所以详细描述一下思路。
假设此时爱丽丝手上有i点(1<=i<=K),并设她此时获胜的概率为f(i)。在不考虑i+W > K的情况下,爱丽丝胜出的概率为:
f(i) = [f(i+1)+f(i+2)+f(i+3)+...+f(i+W-1)+f(i+W)] / W
至此已经初步构成递归,进一步有:
f(i+1) - f(i) = [f(i+W+1) - f(i+1)] / W.
由上式出发,再考虑一下i+W > K情况下的边界条件就可以完成本题,代码如下。这题我真的对着答案想了很久,可能有2个小时吧,可能一是数学功底太差,二是已经把动归忘得差不多了。
class Solution { public: double new21Game(int N, int K, int W) { vector<double> dp(K+1, 1.0); double sum = 0.0; int minN = N-K; for (int i = 1; i <= K; ++i) { if (i <= W) { dp[i] = (sum + min(minN, W - i) + 1) / W; sum += dp[i]; } else { dp[i] = sum / W; sum += dp[i] - dp[i-W]; } } return dp[K]; } };
825这道题有一点值得吐槽,凭什么15岁以下的人不能交朋友啊。。。
这道题其实比较简单,一开始我的想法也很简单,排个序嘛,然后暴力搜就vans了,恭喜你,猪也是这么想的。
这样做会导致时间复杂度特别高,简化的做法是用map统计各个年龄的人数,然后运用一点高中学的排列组合简化计算,代码如下。
class Solution { public: int numFriendRequests(vector<int>& ages) { int res = 0, group = 0, minAge = 0; int map[121] = {0}; for (auto &i: ages) ++map[i]; for (int i = 1; i < 121; ++i) { map[i] += map[i-1]; } for (int i = 15; i < 121; ++i) { minAge = map[i] - map[i / 2 + 7]; group = map[i] - map[i-1]; res += group * (minAge - 1); } return res; } };
深度优先、广度优先都可以,因为个人感觉广度优先比较简单直观,而深度优先一直是我不太懂的方法,所以我采用了深度优先,额外用一个map代表“颜色”就行了。
深度优先就不展开说了,算法导论讲得比我好一万倍,让我这种弱智都理解了,不懂深度优先的建议仔细阅读一下。代码如下。
class Solution { public: unordered_map<Node*, Node*> map; Node* cloneGraph(Node* node) { if (!node) return NULL; if (map.find(node) == map.end()) { map[node] = new Node(node->val, {}); for(auto &neighbor: node->neighbors) { map[node]->neighbors.push_back(cloneGraph(neighbor)); } } return map[node]; } };