【Leetcode周赛】从contest-81开始。(一般是10个contest写一篇文章)

Contest 81 (2018年11月8日,周四,凌晨)

链接:https://leetcode.com/contest/weekly-contest-81

比赛情况记录:结果:3/4, ranking: 440/2797。这次题目似乎比较简单,因为我比赛的时候前三题全做出来了(1:12:39),然后第四题有思路,正在写,没写完,比赛完了写完提交也对了。

【821】Shortest Distance to a Character(第一题 4分)

给了一个单词(字符串)s,和单词中的任意一个字母 c,问单词中的每个字母到 c 的最近距离是多少。 

Example 1:
Input: S = "loveleetcode", C = 'e'
Output: [3, 2, 1, 0, 1, 0, 0, 1, 2, 2, 1, 0]

题解:我是用了一个vector记录了所有字符 c 的下标,然后用遍历整个字符串,用一根指针辅助遍历 c 下标数组做的。时间复杂度 O(N)。写法不够优秀,c 的下标数组可以左边右边填一个元素,就不用写那么多判断了吧?

 1 class Solution {
 2 public:
 3     vector<int> shortestToChar(string S, char C) {
 4         const int n = S.size();
 5         vector<int> idxs;
 6         vector<int> ans(n, -1);
 7         for (int i = 0; i < n; ++i) {
 8             if (S[i] == C) {
 9                 idxs.push_back(i);
10                 ans[i] = 0;
11             }
12         }
13         int p1 = 0;
14         for (int i = 0; i < n; ++i) {
15             if (p1 == 0 && i < idxs[p1]) {
16                 ans[i] = idxs[p1] - i;
17             } else if (p1 + 1 < idxs.size() && i >= idxs[p1] && i <= idxs[p1+1]) {
18                 ans[i] = min(abs(i - idxs[p1]), abs(idxs[p1+1] - i));
19             } else if (p1 + 1 == idxs.size() && idxs[p1] < i) {
20                 ans[i] = i - idxs[p1];
21             }
22             if (p1 + 1 < idxs.size() && i == idxs[p1+1]) {
23                 ++p1;
24             }
25         }
26         return ans;
27     }
28 };
View Code

 

【822】Card Flipping Game (第二题 5分)

给了一排纸牌,纸牌前面和后面都有一个数字,我们可以做两个动作,第一个动作是任意翻动任意的纸牌正反面(形成新的正反面数组),第二个动作是我们拿一张纸牌,如果它反面的数字没有在正面的数组里面出现,那么这个数字就是good,要求返回最小 good 的数字。

题解:我是先把 front 和 back 数组合二为一,然后把大数组做了一个排序。然后遍历正反两面的数组,把正反面数字相同的纸牌上的数字放进了一个set里面,这些数字肯定不是 good 的,因为不论这些纸牌怎么翻,都是一个数字。然后我返回了大数组不在set里面的第一个元素。

 1 class Solution {
 2 public:
 3     int flipgame(vector<int>& fronts, vector<int>& backs) {
 4         const int n = fronts.size();
 5         int ans = 0;
 6         vector<int> tot(fronts);
 7         for (auto b : backs) {
 8             tot.push_back(b);
 9         }
10         sort(tot.begin(), tot.end());
11         set<int> st;
12         for (int i = 0; i < n; ++i) {
13             if (fronts[i] == backs[i]) {
14                 st.insert(fronts[i]);
15             }
16         }
17         for (int i = 0; i < 2 * n; ++i) {
18             if (st.find(tot[i]) == st.end()) {
19                 ans = tot[i];
20                 break;
21             }
22         }
23         return ans;
24     }
25 };
View Code

  

【820】Short Encoding of Words (第三题 6分)(尝试了一下翻译题目,不好翻译,直接贴原题了)

Given a list of words, we may encode it by writing a reference string S and a list of indexes A.

For example, if the list of words is ["time", "me", "bell"], we can write it as S = "time#bell#" and indexes = [0, 2, 5].

Then for each index, we will recover the word by reading from the reference string from that index until we reach a "#" character.

What is the length of the shortest reference string S possible that encodes the given words?

Example:
Input: words = ["time", "me", "bell"]
Output: 10
Explanation: S = "time#bell#" and indexes = [0, 2, 5].
Note:
1 <= words.length <= 2000.
1 <= words[i].length <= 7.
Each word has only lowercase letters.

题解:我一开始想的是把相同后缀的字符串用map分组,然鹅,代码写出来了但是超时。后来仔细想了一下,相同的后缀如果翻转一下字符串就能变成相同的前缀,然后按照字母序sort一下,就能逐条比较了。最后的时间复杂度降低成了O(nlogn),(要排序的复杂度)

 1 class Solution {
 2 public:
 3     int minimumLengthEncoding(vector<string>& words) {
 4         const int n = words.size();
 5         vector<string> newWords(words);
 6         for (auto& w : newWords) {
 7             reverse(w.begin(), w.end());
 8         }
 9         sort(newWords.begin(), newWords.end());
10         vector<string> temp;
11         for (int i = 0; i < n-1; ++i) {
12             string cur = newWords[i], ne = newWords[i+1];
13             int curSize = cur.size(), neSize = ne.size();
14             if (neSize < curSize || ne.substr(0, curSize) != cur) {
15                 temp.push_back(cur);
16                 continue;
17             }
18         }
19         temp.push_back(newWords.back());
20         int ans = 0;
21         for (auto w : temp) {
22             ans += (1 + w.size()); 
23         }
24         return ans;
25         
26     }
27 };
View Code

 

【823】Binary Trees With Factors (第四题 7 分)

 给了一个 unique 的数组 A,题目定义说二叉树的一个非叶子结点的值一定等于它左右儿子的乘积,问这个数组能组成多少种类的二叉树,数组中的元素可以用任意次。因为答案可能很大,所以需要模 1e9 + 7.

Example 1:
Input: A = [2, 4]
Output: 3
Explanation: We can make these trees: [2], [4], [4, 2, 2]

Example 2:
Input: A = [2, 4, 5, 10]
Output: 7
Explanation: We can make these trees: [2], [4], [5], [10], [4, 2, 2], [10, 2, 5], [10, 5, 2].

题解:我首先一个感觉就是应该先每个元素能表达成乘积形式的东西列出来。比如 4 -> (2, 2); 10 ->(2, 5), (5,2)。然后枚举每一个元素为根,然后我开始纠结了一下,难道要dfs吗?结果那么多,我估计dfs不是超时就是要挂。所以就往 dp 上面想。

dp[i] 表示以 A[i] 为根的二叉树的种类,如果 A[i] = A[x] * A[y],那么dp[i] = dp[x] * dp[y]。dp[i] 初始化为 1, 因为这棵树可以选择没有孩子,只有它自己作为根。

然后就是 MOD 了。这种大数我就是容易写挂,不知道为啥,是不是还有什么原理没有摸透。唉。

 1 class Solution {
 2 public:
 3     const int MOD = 1e9 + 7;
 4     int numFactoredBinaryTrees(vector<int>& A) {
 5         int n = A.size();
 6         sort(A.begin(), A.end());
 7         map<int, vector<pair<int, int>>> mp, debugMap;
 8         for (int i = 1; i < n; ++i) {
 9             int p1 = 0, p2 = i - 1;
10             while (p1 <= p2) {
11                 int mul = A[p1] * A[p2];
12                 if (A[i] == mul) {
13                     debugMap[A[i]].push_back(make_pair(A[p1], A[p2]));
14                     mp[i].push_back(make_pair(p1, p2));
15                     if (A[p1] != A[p2]) {
16                         debugMap[A[i]].push_back(make_pair(A[p2], A[p1]));
17                         mp[i].push_back(make_pair(p2, p1));
18                     }
19                     p1++, p2--;
20                 } else if (A[i] > mul) {
21                     ++p1;
22                 } else if (A[i] < mul) {
23                     --p2;
24                 }
25             }
26         }
27         vector<long long> dp(n, 1); //dp[i] 表示用 A[i] 为根的二叉树有几棵
28         for (int i = 0; i < n; ++i) {
29             //int root = A[i];
30             if (mp.find(i) == mp.end()) {continue;}
31             vector<pair<int, int>> vec = mp[i];
32             for (auto p : vec) {
33                 int x = p.first, y = p.second;
34                 dp[i] = (dp[i] + dp[x] * dp[y]) % MOD;
35             }
36         }
37         int ans = 0;
38         for (auto e : dp) {
39             ans = (ans + e) % MOD;
40         }
41         return ans;
42     }
43 };
View Code

 

Contest 82 (2018年11月8日,周四)

链接:https://leetcode.com/contest/weekly-contest-82

比赛情况记录:结果:3/4, ranking:345/2564。这次四道题都不难,我比赛做出来三题,有个逻辑判断的题想了比较久, friends of appropriate ages,这个题推导了半天。第四题没空写了,结果第四题下午写WA了好几次。

Goat Latin(第一题 4分)

 

Friends Of Appropriate Ages(第二题 5分)(这题也要看答案)

 

Most Profit Assigning Work (第三题 7分)(感觉这题还能更快,要记得看答案)

 

Making A Large Island (第四题 8 分)

 

 

Contest 83 (2018年11月12日,周一)

链接:https://leetcode.com/contest/weekly-contest-83

比赛情况记录:比赛结果记录:2/4。 ranking:675/2688。好像这场是随便做了两题签到题就有事出去了orz。(11月21日才写log,有点忘记了orz)第三题我有印象,好像做了,然而超时啊啊啊啊啊。

【830】Positions of Large Groups (第一题 3分)

给了一个小写字母的字符串,每一段相同的字母叫做一个 group, 如果 group 的字母数量 大于等于 3个字符就叫做 large group。返回所有 large group 的开始和结束下标。

Input: "abcdddeeeeaabbbcd"
Output: [[3,5],[6,9],[12,14]]

题解:两根指针扫一遍。

 1 class Solution {
 2 public:
 3     vector<vector<int>> largeGroupPositions(string S) {
 4         const int n = S.size();
 5         vector<vector<int>> ans;
 6         int p1 = 0, p2 = 0;
 7         while (p2 < n) {
 8             while (p2 < n && S[p1] == S[p2]) {
 9                 p2++;
10             }
11             if (p2 - p1 >= 3) {
12                 ans.push_back({p1, p2-1});
13             }
14             p1 = p2;
15         }
16         return ans;
17     }
18 };
View Code

 

【831】Masking Personal Information (第二题 5分)

给了一个字符串,可能是 email address 也可能是 phone number。题目的意思要给这个字符串打码。

如果是 email 的字符串,它一定满足这个格式:"name1@name2.name3",给它 masking 的方法是 name1 只留首尾两个字母,其他的name保留原来格式,但是 所有的 name 都必须是小写字母。

如果是 phone number, 它可能有国家地区编码,也可能没有。一个 phone number 的长度是 10 - 13 个数字,最后 10个数字做 local number,前面可能有 1 - 3 个数字做 country-code。local number masking 之后要保留这个格式:"***-***-DDDD"。

如果有 country-code 的话,country-code 前面的 ‘+’ 和后面的 ‘-’ 需要保留。

Example 1:
Input: "LeetCode@LeetCode.com"
Output: "l*****e@leetcode.com"
Explanation: All names are converted to lowercase, and the letters between the
             first and last letter of the first name is replaced by 5 asterisks.
             Therefore, "leetcode" -> "l*****e".

Example 2:
Input: "AB@qq.com"
Output: "a*****b@qq.com"
Explanation: There must be 5 asterisks between the first and last letter 
             of the first name "ab". Therefore, "ab" -> "a*****b".

Example 3:
Input: "1(234)567-890"
Output: "***-***-7890"
Explanation: 10 digits in the phone number, which means all digits make up the local number.

Example 4:
Input: "86-(10)12345678"
Output: "+**-***-***-5678"
Explanation: 12 digits, 2 digits for country code and 10 digits for local number. 

 题解:模拟题,读懂题意开始搞就行了。

 1 class Solution {
 2 public:
 3     string maskPII(string S) {
 4         const int n = S.size();
 5         if (S.find("@") != string::npos && S.find(".") != string::npos) {
 6             return copeEmail(S);
 7         }
 8         return copePhone(S);
 9     }
10     string copeEmail(string S) {
11         auto pos = S.find("@");
12         string name1 = S.substr(0, pos);
13         for (auto& p : name1) {
14             if (isupper(p)) {
15                 p = tolower(p);
16             }
17         }
18         string name2 = S.substr(pos);
19         //printf("pos = %d, name1 = %s, name2 = %s \n", pos, name1.c_str(), name2.c_str());
20         string newName1 = string(1, name1.front()) + "*****" + string(1, name1.back());
21         for (auto& p : name2) {
22             if (isupper(p)) {
23                 p = tolower(p);
24             }
25         }
26         S = newName1 + name2;
27         return S;
28     }
29     string copePhone(string S) {
30         string newS = "";
31         for (auto p : S) {
32             if (isdigit(p)) {
33                 newS += p;
34             }
35         }
36         const int n = newS.size();
37         if (n < 10) {cout << "err" << endl;}
38         if (n == 10) {
39             S = "***-***-" + newS.substr(n-4);
40         } else {
41             int countryCodeNum = n  - 10;
42             string countryCode(countryCodeNum, '*');
43             S = "+" + countryCode + "-" +  "***-***-" + newS.substr(n-4);
44         }
45         return S;
46     }
47 };
View Code

 

【829】Consecutive Numbers Sum(第三题 7分)

 给了一个数字 N,返回它有几种拆法能把它表示成一段连续的自然数相加。

Example 1:
Input: 5
Output: 2
Explanation: 5 = 5 = 2 + 3
Example 2:
Input: 9
Output: 3
Explanation: 9 = 9 = 4 + 5 = 2 + 3 + 4
Example 3:
Input: 15
Output: 4
Explanation: 15 = 15 = 8 + 7 = 4 + 5 + 6 = 1 + 2 + 3 + 4 + 5
Note: 1 <= N <= 10 ^ 9.

题解:我好像在哪个地方见过这个题,然而解法超时。解法就是用 两个变量 small 和 big,一开始他们两个都是 1, 如果现在的 [small, big] 区间和 summ 小于 N,就 ++big,这样 summ 就会变大。如果现在的 [small, big] 区间和 summ 大于 N,就 ++small, 这样 summ 就会减小。这个是超时解法,时间复杂度应该是 O(N)。(吐了)

 

【828】Unique Letter String(第四题 9分)

这题我看了应该也不是很难。估计我会解。 

 

Contest 84 (2018年11月21日,周三)

链接:https://leetcode.com/contest/weekly-contest-84

比赛情况记录:第三题算法群前两天才出过,所以迅速的用了25分钟AC了三题。结果: 3/4,ranking:104/2421。第四题我用 bfs 和 floyed 都超时了。唉。

【832】Flipping an Image(第一题 3分)

给了一个 0/1 矩阵,按照题意先把每行前后翻转,然后把 0 变成 1,1 变成 0。返回新矩阵。

题解:按照题意解。

 1 class Solution {
 2 public:
 3     vector<vector<int>> flipAndInvertImage(vector<vector<int>>& A) {
 4         const int n = A.size();
 5         for (auto& row : A) {
 6             reverse(row.begin(), row.end());
 7             for (auto& ele : row) {
 8                 ele = 1 - ele;
 9             }
10         }
11         return A;
12     }
13 };
View Code

 

【833】Find And Replace in String(第二题 4分)

给了一个字符串 S,一个下标数组 indexes, 一个原字符串数组 sources, 一个目标字符串数组 targets。如果在 S 中 indexes[i] 开始的子串是 sources[i],就把它替换成 targets[i] (sources[i] 和 target[i] 不是同一个长度)。如果不是那就不用替换。然后题目设定所有的替换都是同时发生的,也就是不存在先把前面替换之后因为 sources[i] 和targets[i] 的长度不同而导致错位什么的。

题解:我是先用了一个 map 存储了可以替换的字符串 S 的下标和对应数组的下标 i。 map<int, int, greater<int>> mp; //idx -> i (pos in sources and targets) 。然后用 greater<int> 使得 map 从大到小排序 key。然后从后往前替换字符串。replace

 1 class Solution {
 2 public:
 3     string findReplaceString(string S, vector<int>& indexes, vector<string>& sources, vector<string>& targets) {
 4         const int n = S.size();
 5         string ret = S;
 6         map<int, int, greater<int>> mp; //idx -> i (pos in sources and targets) 
 7         for (int i = 0; i < indexes.size(); ++i) {
 8             string src = sources[i];
 9             int idx = indexes[i];
10             if (n - i < src.size()) {continue;}
11             bool check = true;
12             for (int k = 0; k < src.size(); ++k) {
13                 if (S[idx+k] != src[k]) {
14                     check = false;
15                     break;
16                 }
17             }
18             if (check) {
19                 mp[idx] = i;
20             }
21         }
22         for (auto p : mp) {
23             int idx = p.first, k = p.second;
24             string src = sources[k], dest = targets[k];
25             ret.replace(idx, (int)src.size(), dest);
26         }
27         return ret;
28     }
29 };
View Code

 

 【835】Image Overlap(第三题 6分)(前两天才在算法群里做完这个题目,所以巨快的做完了orz)

给了两个 0/1 矩阵 A, B(长和宽都是 N), 我们可以上下左右四个方向移动一个矩阵,使得它和另外一个矩阵覆盖,这样的话,每次移动不同的方向和偏移量都会有重叠的 1 的个数。问最多的重叠的 1 的个数是多少。

题解:暴力解, O(N ^4)。先枚举偏移量 O(N^2),再枚举 一个矩阵的位置 O(N^2)。根据这两个东西计算另外一个矩阵的位置。判断累加计算。

 1 class Solution {
 2 public:
 3     int largestOverlap(vector<vector<int>>& A, vector<vector<int>>& B) {
 4         n = A.size();
 5         return max(helper(A, B), helper(B, A));
 6     }
 7     int n = 0;
 8     int helper(const vector<vector<int>>& A, const vector<vector<int>>& B) {
 9         int res = 0;
10         for (int offsetX = 0; offsetX < n; ++offsetX) {
11             for (int offsetY = 0; offsetY < n; ++offsetY) {
12                 int cnt = 0;
13                 for (int i = offsetX; i < n; ++i) {
14                     for (int j = offsetY; j < n; ++j) {
15                         if (A[i][j] && B[i-offsetX][j-offsetY]) {
16                             cnt++;
17                         }
18                     }
19                 }
20                 res = max(res, cnt);
21             }
22         }
23         return res;
24     }
25 };
View Code

discuss里面有 O(N^2) 的解法。然而不一定比这个快,orz

 

【834】Sum of Distances in Tree(第四题 9分)

给了一个无向的树,有 N 个结点, N-1 条边,要求返回一个 ans list,list 里面记录了每一个结点 i 和其他所有结点的距离之和。

Example 1:
Input: N = 6, edges = [[0,1],[0,2],[2,3],[2,4],[2,5]]
Output: [8,12,6,10,10,10]
Explanation: 
Here is a diagram of the given tree:
  0
 / \
1   2
   /|\
  3 4 5
We can see that dist(0,1) + dist(0,2) + dist(0,3) + dist(0,4) + dist(0,5)
equals 1 + 1 + 2 + 2 + 2 = 8.  Hence, answer[0] = 8, and so on.
Note: 1 <= N <= 10000

题解:N 最大可以取到 10000, 我还用了 floyed 或者 bfs 也许就是作死吧。但是根本想不到更快的方法啊orz。

 

 

 

Contest 85 (还没做,待定)

 

Contest 86 (2018年11月21日,周三)

链接:https://leetcode.com/contest/weekly-contest-86

比赛情况记录:结果:3/4,ranking:326/2323。第三题 backtracking 找斐波那契数列调试了好久。第四题没看。orz

【840】Magic Squares In Grid(第一题 3分)

【841】Keys and Rooms(第二题 5分)

【842】Split Array into Fibonacci Sequence(第三题 6分)

【843】Guess the Word(第四题 8分)

 

posted @ 2018-11-21 22:18  zhangwanying  阅读(612)  评论(0编辑  收藏  举报