【Leetcode周賽】從contest-81開始。(通常是10個contest寫一篇文章)

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

連接:https://leetcode.com/contest/weekly-contest-81
git

比賽狀況記錄:結果:3/4, ranking: 440/2797。此次題目彷佛比較簡單,由於我比賽的時候前三題全作出來了(1:12:39),而後第四題有思路,正在寫,沒寫完,比賽完了寫完提交也對了。算法

【821】Shortest Distance to a Character(第一題 4分)數組

給了一個單詞(字符串)s,和單詞中的任意一個字母 c,問單詞中的每一個字母到 c 的最近距離是多少。 app

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 的下標數組能夠左邊右邊填一個元素,就不用寫那麼多判斷了吧?ide

 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 的數字。spa

題解:我是先把 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分)(嘗試了一下翻譯題目,很差翻譯,直接貼原題了)debug

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分)

相關文章
相關標籤/搜索