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

Posted zhangwanying

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 的字符串,它一定满足这个格式:"[email protected]",给它 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: "[email protected]"
Output: "l*****[email protected]"
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: "[email protected]"
Output: "a*****[email protected]"
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 
", 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

比赛情况记录:

 

Contest 85 (还没做,待定)

 

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

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

比赛情况记录:

 



以上是关于Leetcode周赛从contest-81开始。(一般是10个contest写一篇文章)的主要内容,如果未能解决你的问题,请参考以下文章

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

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

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

LeetCode笔记:Biweekly Contest 81

LeetCode周赛252场:时隔半年再来练习

LeetCode周赛252场:时隔半年再来练习