【Leetcode周赛】从contest-51开始。(一般是10个contest写一篇文章)
Contest 51 (2018年11月22日,周四早上)(题号681-684)
链接:https://leetcode.com/contest/leetcode-weekly-contest-51
比赛结果记录:3/4,ranking:270/2879。第三题有点类似于图的最小生成树,第四题似乎是很火的种花题(第四题我好像几个月之前做过,有印象,当时也是自己做的)。
【682】Baseball Game(第一题 3分)
You're now a baseball game point recorder.
Given a list of strings, each string can be one of the 4 following types:
Integer
(one round's score): Directly represents the number of points you get in this round."+"
(one round's score): Represents that the points you get in this round are the sum of the last twovalid
round's points."D"
(one round's score): Represents that the points you get in this round are the doubled data of the lastvalid
round's points."C"
(an operation, which isn't a round's score): Represents the lastvalid
round's points you get were invalid and should be removed.
Each round's operation is permanent and could have an impact on the round before and the round after.
You need to return the sum of the points you could get in all the rounds.
Example 1: Input: ["5","2","C","D","+"] Output: 30 Explanation: Round 1: You could get 5 points. The sum is: 5. Round 2: You could get 2 points. The sum is: 7. Operation 1: The round 2's data was invalid. The sum is: 5. Round 3: You could get 10 points (the round 2's data has been removed). The sum is: 15. Round 4: You could get 5 + 10 = 15 points. The sum is: 30. Example 2: Input: ["5","-2","4","C","D","9","+","+"] Output: 27 Explanation: Round 1: You could get 5 points. The sum is: 5. Round 2: You could get -2 points. The sum is: 3. Round 3: You could get 4 points. The sum is: 7. Operation 1: The round 3's data is invalid. The sum is: 3. Round 4: You could get -4 points (the round 3's data has been removed). The sum is: -1. Round 5: You could get 9 points. The sum is: 8. Round 6: You could get -4 + 9 = 5 points. The sum is 13. Round 7: You could get 9 + 5 = 14 points. The sum is 27. Note: The size of the input list will be between 1 and 1000. Every integer represented in the list will be between -30000 and 30000.
题解:模拟题,用了一个deque做的模拟,应该可以有不用数据结构的方法?2 pass
1 class Solution { 2 public: 3 int calPoints(vector<string>& ops) { 4 deque<int> dq; 5 const int n = ops.size(); 6 for (auto s : ops) { 7 if (s == "C") { 8 if (!dq.empty()) { 9 dq.pop_back(); 10 } 11 } else if (s == "D") { 12 if (!dq.empty()) { 13 dq.push_back(dq.back() * 2); 14 } 15 } else if (s == "+") { 16 int numA = 0; 17 if (!dq.empty()) { 18 numA = dq.back(); 19 dq.pop_back(); 20 if (!dq.empty()) { 21 int temp = dq.back() + numA; 22 dq.push_back(numA); 23 dq.push_back(temp); 24 } else { 25 dq.push_back(numA); 26 } 27 } 28 } else { 29 dq.push_back(stoi(s)); 30 } 31 } 32 int ret = 0; 33 while (!dq.empty()){ 34 ret += dq.front(); 35 dq.pop_front(); 36 } 37 return ret; 38 } 39 };
【681】Next Closest Time(第二题 6分)
给了一个时间表示,格式是 "HH:MM",用现在时间表示的这些数字形成下一个距离现在最近的时间字符串,并且返回.
You may assume the given input string is always valid. For example, "01:34", "12:09" are all valid. "1:34", "12:9" are all invalid. Example 1: Input: "19:34" Output: "19:39" Explanation: The next closest time choosing from digits 1, 9, 3, 4, is 19:39, which occurs 5 minutes later. It is not 19:33, because this occurs 23 hours and 59 minutes later. Example 2: Input: "23:59" Output: "22:22" Explanation: The next closest time choosing from digits 2, 3, 5, 9, is 22:22. It may be assumed that the returned time is next day's time since it is smaller than the input time numerically.
题解:感觉和产生下一个回文串比较类似,先把这四个数字记下来,然后从后往前找第一个在合理的范围内能变得更大的数字。因为是时间,所以时针最多到23,分针最多到59,找到第一个能变得更大的数字就把它变得更大,然后把它后面的数字都变成最小。如果找不到这样的一数字,比如eg2的 23:59,就把所有的数字变成最小的数字,算作新的一天。
1 class Solution { 2 public: 3 string nextClosestTime(string time) { 4 set<int> st; 5 int minn = 10; 6 for (int i = 0; i < 5; ++i) { 7 if (isdigit(time[i])) { 8 int t = time[i] - '0'; 9 minn = min(t, minn); 10 st.insert(t); 11 } 12 } 13 if (st.size() == 1) {return time;} //invalid 14 string ret = time; 15 for (int i = 4; i >= 0; --i) { 16 char c = ret[i]; 17 int t = c - '0'; 18 auto iter = upper_bound(st.begin(), st.end(), t); 19 if (iter == st.end()) {continue;} 20 if (i == 0 && *iter > 2) { 21 continue; 22 } 23 if (i == 1 && *iter > 4 && ret[0] == '2') { 24 continue; 25 } 26 if (i == 3 && *iter > 5) { 27 continue; 28 } 29 ret[i] = (*iter) + '0'; 30 for (int k = i + 1; k < 5; ++k) { 31 if (isdigit(ret[k])) { 32 ret[k] = minn + '0'; 33 } 34 } 35 break; 36 } 37 if (ret == time) { 38 for (auto& c : ret) { 39 if (isdigit(c)) { 40 c = minn + '0'; 41 } 42 } 43 } 44 return ret; 45 46 } 47 };
【684】Redundant Connection(第三题 8分)
在本题中,树是一个无环的无向图。输入一个N个结点(编号是1~N)的图,有一条边是多余的,把这条边找出来。
Example 1: Input: [[1,2], [1,3], [2,3]] Output: [2,3] Explanation: The given undirected graph will be like this: 1 / \ 2 - 3 Example 2: Input: [[1,2], [2,3], [3,4], [1,4], [1,5]] Output: [1,4] Explanation: The given undirected graph will be like this: 5 - 1 - 2 | | 4 - 3 Note: The size of the input 2D-array will be between 3 and 1000. Every integer represented in the 2D-array will be between 1 and N, where N is the size of the input array.
题解:我是用并查集解的。对于每一条边的两个结点,如果他们的爸爸不是同一个爸爸,那么就 unoin 这两个结点,如果他们两个的爸爸是同一个爸爸,就说明这条边多余了,直接返回这条边就行了。
1 class Solution { 2 public: 3 int findfather(int x) { 4 return x == father[x] ? x : findfather(father[x]); 5 } 6 void unionNode(int x, int y) { 7 x = findfather(x); 8 y = findfather(y); 9 if (x == y) { return; } 10 father[y] = x; 11 } 12 13 vector<int> findRedundantConnection(vector<vector<int>>& edges) { 14 n = edges.size(); 15 father.resize(n+1); //redundant 0 16 for (int i = 0; i < n+1; ++i) { 17 father[i] = i; 18 } 19 vector<int> ret; 20 for (auto e : edges) { 21 int u = min(e[0], e[1]), v = max(e[0], e[1]); 22 if (findfather(v) == findfather(u)) { 23 ret = e; 24 break; 25 } else { 26 unionNode(u, v); 27 } 28 } 29 return ret; 30 } 31 int n = 0; 32 vector<int> father; 33 34 };
【683】K Empty Slots(第四题 9分)(经典的种花题)
给了 N 个花槽,有 N 朵花每天开一朵,用 flower[i] = x 表示在第 i 天在位置 x 开出了一朵花,花开了之后就会一直开着,不会凋谢。问是否存在这么一天,某个位置的一朵花开了,然后另外一朵花也在开花的状态,这两朵花中间有恰好有 k 个花槽,这 k 个花槽都没有开花。
题解:这题其实之前做过,第一次做就会做,有点倒排索引的感觉。我们用另外一个数组 bloom[pos] = day,表示第pos个位置的花在第 day 天开。然后我们从第二天开始枚举,找到第二天开花的位置,然后用 k 计算出另外一朵花的位置,看是否已经开花,如果已经开花了,就看一下中间的 k 个花槽是不是都没开花,如果都满足条件,直接返回这一天。
我今天第一次写的时候犯了一个误区,就是我错误的认为如果今天开花,那么它对应的另外一朵花一定是昨天开的,事实上它对应的花可以在今天前面的任何一天开花。所以会错。
1 //这题一开始有个思维误区,就是我懵逼的认为如果满足条件的那天开的那朵花,与这朵花相对应的另外一朵一定开在满足条件的前一天orz。 2 class Solution { 3 public: 4 int kEmptySlots(vector<int>& flowers, int k) { 5 const int n = flowers.size(); 6 vector<int> bloom(n + 1, 0); 7 for (int i = 0; i < flowers.size(); ++i) { 8 int day = i+1, pos = flowers[i]; //day (1, n) 9 bloom[pos] = day; 10 } 11 //find pos flowers[day-1] 12 for (int day = 2; day < n; ++day) { 13 int posToday = flowers[day-1]; 14 for (int m = 0; m < 2; ++m) { 15 int posPre = m == 0 ? (posToday + k + 1) : (posToday - k - 1); 16 if (posPre > 0 && posPre <= n) { 17 int preDay = bloom[posPre]; 18 if (preDay > day) {continue;} 19 bool valid = true; 20 for (int i = min(posPre, posToday) + 1; i < max(posPre, posToday); ++i) { 21 if (bloom[i] < day) { 22 valid = false; 23 break; 24 } 25 } 26 if (valid) {return day;} 27 } 28 } 29 } 30 return -1; 31 } 32 };
Contest 52 (2018年11月24日,周六下午)(题号686-689)
比赛情况记录:2/4,rank:485/2615. 第三题概率题不会做,第四题感觉方法对了,但是代码写出来踩内存了RE,调试了一晚上也没搞明白到底哪里问题。mdzz。
链接:https://leetcode.com/contest/leetcode-weekly-contest-52
【686】Repeated String Match(第一题 3分)
第一题给了两个字符串,A 和 B, 问 A 倍增几倍之后能不能把 B 变成它的子串。返回 A 倍增的最小次数,如果无论怎么倍增 B 都不是子串的话,返回 -1。
题解:本题一开始还有点卡住了orz,尴尬。先求 A B 的长度,如果 A 的长度直接比 B 大的话,最多 2 个 A可以搞成 B。同理,先求 Asize / Bsize,先把 A 的长度倍增成比B大一点点或者相等,如果这时候 B 还不是 A 的子串,就把再加一个 A,如果加了还不是就是不是了。
1 class Solution { 2 public: 3 int repeatedStringMatch(string A, string B) { 4 const int Asize = A.size(), Bsize = B.size(); 5 int t = Bsize / Asize; 6 if (Asize * t < Bsize) {++t;} 7 string newA = ""; 8 for (int i = 0; i < t; ++i) { 9 newA += A; 10 } 11 if (newA.find(B) == string::npos) { 12 newA += A; 13 if (newA.find(B) == string::npos) { 14 return -1; 15 } 16 return t+1; 17 } 18 return t; 19 } 20 };
【687】Longest Univalue Path(第二题 5分)
【688】Knight Probability in Chessboard(第三题 6分)
【689】Maximum Sum of 3 Non-Overlapping Subarrays(第四题 8分)
Contest 53 ()(题号)
Contest 54 ()(题号)
Contest 55 ()(题号)
Contest 56 ()(题号)
Contest 57 ()(题号)
Contest 58 ()(题号)
Contest 59 ()(题号)
Contest 60 (2018年12月26日,周三早上)(题号)
链接:https://leetcode.com/contest/weekly-contest-60
比赛结果记录:3/4,没开 virtual,所以我也没有记录具体的时间。orz。第四题研究了一会儿,需要递归做。然而自己放弃了没写出来。
【733】Flood Fill(第一题 3分)
给了一个二维的matrix,和一个点坐标,和新颜色。把这个点周围四联通区域和该点相同颜色的点,都染成新的颜色。
题解:无
1 class Solution { 2 public: 3 vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int newColor) { 4 n = image.size(), m = image[0].size(); 5 oric = image[sr][sc]; 6 if (oric == newColor) {return image;} 7 floodfill (image, sr, sc, newColor); 8 return image; 9 } 10 int n, m; 11 int oric; 12 void floodfill(vector<vector<int>>& image, int cur_x, int cur_y, const int color) { 13 image[cur_x][cur_y] = color; 14 for (int i = 0; i < 4; ++i) { 15 int newx = cur_x + dirx[i], newy = cur_y + diry[i]; 16 if (newx < 0 || newx >= n || newy < 0 || newy >= m || image[newx][newy] != oric) { 17 continue; 18 } 19 floodfill(image, newx, newy, color); 20 } 21 } 22 int dirx[4] = {-1, 0, 1, 0}; 23 int diry[4] = {0, -1, 0, 1}; 24 };
【734】Sentence Similarity(第二题 3分)
给了两个单词数组,words1,words2,和一个相似单词的词典,判断这两个单词数组是不是相似。相似的条件为(1)两个数组元素个数一致;(2)words1[i], words2[i] 在相似词典中有映射关系,或者words1[i] 和 words2[i] 这两个单词相同。
题解:无
1 class Solution { 2 public: 3 bool areSentencesSimilar(vector<string>& words1, vector<string>& words2, vector<pair<string, string>> pairs) { 4 const int n1 = words1.size(), n2 = words2.size(); 5 if (n1 != n2) {return false;} 6 set<pair<string, string>> st(pairs.begin(), pairs.end()); 7 bool flag = true; 8 for (int i = 0; i < n1; ++i) { 9 string s1 = words1[i], s2 = words2[i]; 10 if (s1 == s2) {continue;} 11 pair<string, string> p1 = make_pair(s1, s2), p2 = make_pair(s2, s1); 12 if (st.find(p1) == st.end() && st.find(p2) == st.end()) { 13 flag = false; 14 break; 15 } 16 } 17 return flag; 18 } 19 };
【735】Asteroid Collision(第三题 5分)
给了一个数组 asteroids 代表一排小行星,元素绝对值代表行星大小,正数代表行星向右,负数代表向左。(如果前面行星向右,后面行星向左,就一定会相撞。但是如果同向或者相背,就肯定不会相撞)如果两颗行星相撞,小的会爆炸,如果大小相同就都爆炸。问最后剩下的行星,返回这个数组。
题解:用一个 vector 或者 deque 存储已经遍历过的行星,如果当前元素是负数,就要一直和前面的正数行星相撞,直到前面没有正数行星为止。有点类似业务逻辑题了。时间复杂度是 O(N)。本题用vector更合适。
1 class Solution { 2 public: 3 vector<int> asteroidCollision(vector<int>& asteroids) { 4 const int n = asteroids.size(); 5 deque<int> dq; 6 for (auto ast : asteroids) { 7 if (dq.empty()) { 8 dq.push_back(ast); 9 } else { 10 bool needPush = true; 11 while (!dq.empty() && dq.back() > 0 && ast < 0) { 12 if (abs(dq.back()) == abs(ast)) { 13 dq.pop_back(); 14 needPush = false; 15 break; 16 } else if (abs(dq.back() < abs(ast))) { 17 dq.pop_back(); 18 } else { 19 needPush = false; 20 break; 21 } 22 } 23 if (needPush) { 24 dq.push_back(ast); 25 } 26 } 27 } 28 vector<int> ret(dq.size()); 29 int i = 0; 30 while (!dq.empty()) { 31 ret[i++] = dq.front(); 32 dq.pop_front(); 33 } 34 return ret; 35 } 36 };
【】Parse Lisp Expression(第四题 9分)