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

Contest 91 (2018年10月24日,週三)

連接:https://leetcode.com/contest/weekly-contest-91/node

模擬比賽狀況記錄:第一題檸檬攤的那題6分鐘AC,而後是第二題樹的距離K的結點那題比較久,大概寫了30分鐘,第三題翻轉矩陣那題第一次提交錯誤了,列的優化方法思路錯了,WA。後來比賽時間到了才改過來。最後一題最短子數組的和比K大的這題不會作。git

【860】Lemonade Change   (第一題)程序員

一個檸檬攤,有一隊人排隊要買檸檬,一個5刀,一開始攤主沒有零錢,買檸檬的人給的錢有5刀,10刀,20刀的,問攤主是否能找開錢。面試

題解:直接模擬。算法

 1 class Solution {
 2 public:
 3     bool lemonadeChange(vector<int>& bills) {
 4         const int n = bills.size();
 5         if (n == 0) { return true; }
 6         map<int, int> money;
 7         for (auto& bill : bills) {
 8             if (bill == 5) {
 9                 money[5]++;
10             } else if (bill == 10) {
11                 if (money.find(5) == money.end() || money[5] == 0) {
12                     return false;
13                 }
14                 money[5]--, money[10]++;
15             } else if (bill == 20) {
16                 if (money[10] >= 1 && money[5] >= 1) {
17                     money[10]--; money[5]--;
18                 } else if (money[5] >= 3) {
19                     money[5] -= 3;
20                 } else {
21                     return false;
22                 }
23                 money[20]++;
24             }
25         }
26         return true;
27     }
28 };
View Code

  

【861】Score After Flipping Matrix  (第三題)數組

給了一個0,1矩陣,咱們每次能把每一行或者每一列的0,1作翻轉,(0變成1,1變成0)。而後咱們把每行的二進制數加起來,問最大和是多少。數據結構

題解:這個題目有點像二進制的豎式加法,對於每一行來講,高位爲1數才大,因此咱們比較翻轉前和翻轉後數的大小就好了。對於每一列來講,至關於同位相加,咱們想要儘量多的 1, 因此咱們數 1 的個數,1 的個數比 0 的個數少就翻轉。less

 1 //這個題目行的翻轉至關於高低位的翻轉,咱們但願每行的數字最大,那麼每一行表明的數字就要比它翻轉之後的大,否則咱們就要翻轉。
 2 //列的翻轉至關於作豎式加法時候的同位相加,咱們但願同一列的 1 儘量的多,因此若是這一列 0 的數量比 1 的數量多了,咱們就要翻轉 01 .
 3 class Solution {
 4 public:
 5     int matrixScore(vector<vector<int>>& A) {
 6         const int n = A.size(), m = A[0].size();
 7         for (auto& row : A) {
 8             row = getLargerRows(row);
 9         }
10       
11         for (int j = 0; j < m; ++j) {
12             vector<int> col(n);
13             for (int i = 0; i < n; ++i) {
14                 col[i] = A[i][j];
15             }
16             col = getLargerCols(col);    
17             for (int i = 0; i < n; ++i) {
18                 A[i][j] = col[i];
19             }
20         }
21         int res = 0;
22         for (int i = 0; i < n; ++i) {
23             res += getDecimal(A[i]);
24         }
25         return res;   
26     }
27     
28     vector<int> getLargerRows(const vector<int>& ori) {
29         string strOri = "", strNew = "";
30         for (auto& c : ori) {
31             strOri += to_string(c);
32             strNew += to_string(1 - c);
33         }
34         if (strOri >= strNew) {
35             return ori;
36         } 
37         vector<int> neww(ori);
38         for (auto& c : neww) {
39             c = 1- c;
40         }
41         return neww;
42     }
43     
44     
45     vector<int> getLargerCols(vector<int>& ori) {
46         const int n = ori.size();
47         int cnt1 = 0;
48         for (auto& ele : ori) {
49             if (ele) { ++cnt1; }
50         }
51         if (cnt1 >= n - cnt1) {return ori;}
52         for (auto& ele : ori) {
53             ele = 1 - ele;
54         }
55         return ori;
56     }
57     
58     int getDecimal(const vector<int>& vec) {
59         int res = 0;
60         for (int i = 0; i < vec.size(); ++i) {
61             res = (res * 2) + vec[i];
62         }
63         //printf ("%d ", res);
64         return res;
65     }
66     
67     
68     void print(vector<vector<int>>& mat) {
69         const int n = mat.size(), m = mat[0].size();
70         for (int i = 0; i < n; ++i) {
71             for (int j = 0; j < m; ++j) {
72                 printf("%d ", mat[i][j]);
73             }
74             printf("\n");
75         }
76         return;
77     }
78 };
View Code

 

【862】Shortest Subarray with Sum at Least K   (monotonic queue,2018年10月25日學習)(第四題)ide

給了一個數組 A 有正有負和一個正整數K,咱們要求最短的子數組長度使得子數組的和大於K。函數

題解:看到數組大小是 50000,因此確定不能用  O(N^2)  的算法暴力枚舉全部子數組。最近學習了單調隊列這種數據結構(deque實現)。結果嘗試寫了,仍是思路不對。哈哈。

看了答案,說咱們能夠先求A數組的前綴和P數組。而後用單調隊列搞一下就好了。單調隊列怎麼搞,解釋以下:

P [i]  表明 A數組前 i 個數的前綴和。 咱們想要獲得 P[y] - P[x] >= K ,(0  <= x < y ) 。咱們的目標是優化 min (y - x) 。

經過觀察, 咱們能夠發現 (1)單調隊列中的P數組必須是遞增的,緣由咱們能夠用反證法,咱們假設 x1 < x2 && P[x1] > P[x2] ,對於一個固定的 y, P[y] - P[x] >= K ,變換一下就變成 P [x] <= P[y] - K,  咱們假設 P[x1]  <= P[y] - K ,那麼必然有  P [x2] < P[x1] < P[y] - K 。然而由於 x2  > x1 ,因此 x2 的答案可能比 x1 優秀。因此單調隊列中的 P 數組必然是遞增的。

(2)對於 一個 x 來講,假如咱們已經找到了一個 P[y1] 跟它組成了一個區間子數組知足大於等於 K 的條件,那麼這個 x 就能夠從隊列裏面彈出去了,由於後面的 y2 即便知足條件也確定不如當前的 y1 優秀。

 1  //這題是單調隊列 monotonic queue
 2 class Solution {
 3 public:
 4     int shortestSubarray(vector<int>& A, int K) {
 5         const int n = A.size();
 6         int ans = n + 1;
 7         vector<int> summ (n + 1, 0);
 8         for (int i = 1; i < n + 1; ++i) {
 9             summ[i] = summ[i-1] + A[i-1];
10         }
11         deque<int> dq;
12         for (int i = 0; i < n + 1; ++i) {
13             int y = summ[i];
14             while (!dq.empty() && summ[dq.back()] > y) {
15                 dq.pop_back();
16             }
17             while (!dq.empty() && y - summ[dq.front()] >= K) {
18                 ans = min(ans, i - dq.front());
19                 dq.pop_front();
20             }
21             dq.push_back(i);
22         }
23         return ans == n + 1 ? -1 : ans;
24     }
25 };
View Code

 

【863】All Nodes Distance K in Binary Tree (第二題)

給了一棵二叉樹和一個結點 target,求距離 target 長度爲 K 的結點有哪些。

題解:結果能夠是target的子孫或者target的父節點的其餘兒子的子孫。我用了一個vector記錄從根節點到target結點的路徑,而後把路徑上每一個結點的其餘兒子都找了一遍。

 1 /**
 2  * Definition for a binary tree node.
 3  * struct TreeNode {
 4  *     int val;
 5  *     TreeNode *left;
 6  *     TreeNode *right;
 7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 8  * };
 9  */
10 
11 class Solution {
12 public:
13     #define NONE 0
14     #define LEFT 1
15     #define RIGHT 2
16     
17     vector<int> distanceK(TreeNode* root, TreeNode* target, int K) {
18         if (!root || !target) { return vector<int>(); }
19         if (K == 0) {ans = {target->val};  return ans;}
20         findPath(root, target);
21         
22         for (int i = 0; i < path.size(); ++i) {
23             if (K - i < 0) { break; }
24             int dir = NONE;
25             if (i > 0) {
26                 if (path[i-1] == path[i]->left) {
27                     dir = RIGHT;
28                 } else if (path[i-1] == path[i]->right) {
29                     dir = LEFT;
30                 }
31             }
32             findChild(path[i], 0, K - i, dir);
33         }
34         return ans;
35     }
36     
37     void findChild(TreeNode* cur, int height, const int K, int dir) {
38         if (height == K) {
39             ans.push_back(cur->val);
40             return;
41         }
42         if (cur->left && dir != RIGHT) {
43             findChild(cur->left, height+1, K, NONE);
44         }
45         if (cur->right && dir != LEFT) {
46             findChild(cur->right, height+1, K, NONE);
47         }
48         return;
49     }
50     
51     bool findPath(TreeNode* cur, TreeNode* target) {
52         if (!cur) {return false;} 
53         if (cur == target) {
54             path.push_back(cur);
55             return true; 
56         }
57         if (cur->left) {
58             if (findPath(cur->left, target)) {
59                 path.push_back(cur);
60                 return true;
61             }
62         }
63         if (cur->right) {
64             if (findPath(cur->right, target)) {
65                 path.push_back(cur);
66                 return true;
67             }
68         }
69         return false; 
70     }  
71     
72     vector<int> ans;
73     vector<TreeNode*> path;
74 };
View Code

 

Contest 92 (2018年10月25日,週四,題號 864-867)

連接:https://leetcode.com/contest/weekly-contest-92/

比賽狀況:第一題3分鐘,第二題少於20分鐘左右,而後從第三題就開始坑。第三題跟2014年的亞馬遜的一個筆試題很像,就是求比N大的第一個迴文數字,而後加上判斷這個數是否是素數。第三題還沒debug完畢,比賽就結束了。第四題沒看。

【867】Transpose Matrix  (第一題 2分)

題意就是把一個二維數組旋轉90度,行變成列,列變成行。

題解:直接作。

 1 class Solution {
 2 public:
 3     vector<vector<int>> transpose(vector<vector<int>>& A) {
 4         const int n = A.size(), m = A[0].size();
 5         vector<vector<int>> mat(m, vector<int>(n, 0));
 6         for (int i = 0; i < m; ++i) {
 7             for (int j = 0; j < n; ++j) {
 8                 mat[i][j] = A[j][i];
 9             }
10         }
11         return mat;
12     }
13 };
View Code

 

【865】Smallest Subtree with all the Deepest Nodes (第二題 5分)

一棵二叉樹,找到它全部最深的子節點的最小公共祖先。(好像是lca????不肯定,可是仍是本身作出來了)

題解:先dfs這棵樹,而後找到最大的height,dfs的同時記錄全部的路徑保存在數組裏面。而後從路徑的數組裏面挑出和最大height長度同樣的路徑,在這些路徑中找一個結點 i, 知足若是 i 不是最後一個結點,那麼必然存在兩條路徑 path1[i+1] != path2[i+1]

 1 /**
 2  * Definition for a binary tree node.
 3  * struct TreeNode {
 4  *     int val;
 5  *     TreeNode *left;
 6  *     TreeNode *right;
 7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 8  * };
 9  */
10 class Solution {
11 public:
12     TreeNode* subtreeWithAllDeepest(TreeNode* root) {
13         if (!root) {return root;}
14         vector<TreeNode*> temp; 
15         getPath(root, temp, 0);
16         for (auto& p : path) {
17             if (p.size() == globalHeight) {
18                 maxPath.push_back(p);
19             }
20         }
21         //找最後一個每條路徑都同樣的結點。
22         TreeNode* firstCommonNode = root;
23         for (int i = 1; i < globalHeight; ++i) {
24             TreeNode* node = maxPath[0][i];
25             for (int j = 1; j < maxPath.size(); ++j) {
26                 if (maxPath[j][i] != node) {
27                     return firstCommonNode;
28                 }
29             }
30             firstCommonNode = node;
31         }
32         return firstCommonNode;
33         
34     }
35     //dfs,獲取最大高度和全部路徑。
36     void getPath(TreeNode* root, vector<TreeNode*>& temp, int height) {
37         if (!root) { 
38             path.push_back(temp);
39             globalHeight = max(globalHeight, height);
40             return;
41         }
42         temp.push_back(root);
43         getPath(root->left, temp, height + 1);
44         getPath(root->right, temp, height + 1);
45         temp.pop_back();
46         return;
47     }
48     
49     vector<vector<TreeNode*>> path;
50     vector<vector<TreeNode*>> maxPath;
51     int globalHeight = 0;
52 };
View Code

 

【866】Prime Palindrome(第三題 7分)

題意很簡單,就是給了一個數字N,要求大於等於N的第一個迴文素數

題解:這題其實一開始有兩個思路,第一個思路是先找比N大的素數,而後再判斷它是否是迴文;第二個思路是先找比N大的迴文數,而後判斷它是否是素數。我是先找回文而後再判斷是否是素數的。

這題有個標準小題就是如何求比N大的第一個素數。這個作法見:https://blog.csdn.net/cjllife/article/details/39938187

算法如圖所示:

當 num 是一位數的時候,num 小於 9 就返回 num + 1, num 等於 9 返回 11。

而後咱們來看 num 是個 n 位數的狀況,(1)當 n 是個奇數的時候,num 的前半段咱們定義爲比較長的半段(half)。咱們從中間位置開始往兩邊找,找到第一個兩邊不對稱的位置,p1 爲左邊不對稱的下標, p2爲右邊不對稱的下標,若是 num[p1] < num[p2],或者都掃描完了發現兩邊徹底對稱,那麼就把 前半段(half)+1。注意若是加一之後進位了從 x 位變成 x+1 位了要特殊判斷,特殊值寫一下就能找到規律。而後加一以後的數就是新的數的前半段,後半段按照前半段翻轉便可。若是 num[p1] > num[p2] 的話,咱們直接翻轉前半段half就好了。(2).同理,若是 n 是偶數的時候,前半段和後半段徹底長度相同。咱們從中間位置開始往兩邊找,依舊找 p1, p2。剩下的同理(1)。

總之寫的 if-else 比較多,要注意好好測試。

  1 //先構造迴文,再判斷是否是素數,比 N 大的迴文數怎麼構造。
  2 class Solution {
  3 public:
  4     int primePalindrome(int N) {
  5         if (isPalindrome(N) && isPrime(N)) {
  6             return N;
  7         }
  8         int palin = N;
  9         do {
 10             //printf("palin = %d \n", palin);
 11             palin = getNextGreaterPalindrome(palin); 
 12             
 13         } while (!isPrime(palin));
 14         return palin;
 15     }
 16     bool isPalindrome(int num) {
 17         string strN = to_string(num);
 18         int start = 0, end = strN.size()-1;
 19         while (start < end) {
 20             if (strN[start] != strN[end]) {
 21                 return false;
 22             }
 23             start++, end--;
 24         }
 25         return true;
 26     }
 27     bool isPrime(int num) {
 28         if (num == 1) {return false;}
 29         for (int i = 2; i <= sqrt(num); ++i) {
 30             if (num % i == 0) {
 31                 return false;
 32             }
 33         }
 34         return true;
 35     }
 36     int getNextGreaterPalindrome(int num) {
 37         if (num <= 9) {
 38             return num == 9 ? 11 : num + 1;
 39         }
 40         string strNum = to_string(num);
 41         const int n = strNum.size();
 42         int halfIdx = (n - 1) / 2;  //n = 3, halfIdx = 1; n = 4, halfIdx = 1;
 43         string strHalf = "", strNew = "";
 44         if (n & 1) { //odd size
 45             int p1 = halfIdx - 1, p2 = halfIdx + 1;
 46             while (p1 >= 0 && p2 < n) {
 47                 if (strNum[p1] != strNum[p2]) {
 48                     break;
 49                 }
 50                 p1--, p2++;
 51             }
 52             if (p1 == -1 || strNum[p1] < strNum[p2]) {  //increase by 1
 53                 strHalf = strNum.substr(0, halfIdx + 1);
 54                 int intHalf = atoi(strHalf.c_str());
 55                 ++intHalf;
 56                 string strHalfNew = to_string(intHalf);
 57                 string t = strHalfNew.substr(0, strHalfNew.size()-1);
 58                 reverse(t.begin(), t.end());
 59                 strNew = strHalfNew + t;
 60                 
 61             } else {
 62                 strHalf = strNum.substr(0, halfIdx);
 63                 string t = strHalf;
 64                 reverse(t.begin(), t.end());
 65                 strNew = strHalf + strNum[halfIdx] + t;
 66             }
 67         } else { // even size
 68             int p1 = halfIdx, p2 = halfIdx + 1;
 69             while (p1 >= 0 && p2 < n) {
 70                 if (strNum[p1] != strNum[p2]) {
 71                     break;
 72                 }
 73                 p1--, p2++;
 74             }
 75             //printf("p1 = %d, p2 = %d ,strNum[p1] = %c, strNum[p2] = %c \n", p1, p2, strNum[p1], strNum[p2]);
 76             if (p1 == -1 || strNum[p1] < strNum[p2]) {  //increase by 1
 77                 strHalf = strNum.substr(0, halfIdx + 1);
 78                 int intHalf = atoi(strHalf.c_str());
 79                 ++intHalf;
 80                 string strHalfNew = to_string(intHalf);
 81                 string t = strHalfNew;
 82                 reverse(t.begin(), t.end());
 83                 
 84                 // 是否有進位。。。
 85                 if ((int)strHalfNew.size() != (int)strHalf.size()) {
 86                     strNew = strHalfNew + t.substr(1, (int)strHalfNew.size()-1);
 87                 } else {
 88                     strNew = strHalfNew + t;
 89                 }           
 90             } else {
 91                 strHalf = strNum.substr(0, halfIdx  + 1);
 92                 string t = strHalf; 
 93                 reverse(t.begin(), t.end());
 94                 strNew = strHalf  + t;
 95             }
 96         }
 97         
 98         //string -> int
 99         int res = atoi(strNew.c_str());
100         return res;
101     }
102     
103     
104 };
View Code

 

【864】Shortest Path to Get All Keys (第四題 9分)

 

 

 

 

Contest 93 (2018年10月26日,週五,題號 868-871)

連接:https://leetcode.com/contest/weekly-contest-93/

比賽狀況記錄:前三題都不難,甚至於最後放棄的第四題我以爲我好像見過。(42min 3道題)

【868】Binary Gap (第一題 3分)

給了一個正整數 N,返回 N 的二進制表示中,兩個連續 1 的最長距離, 若是沒有兩個連續的 1,就直接返回 0。 好比 N = 6, 二進制是 110, 那麼就返回 1,好比 N = 5,二進制是 101,就返回 2。

題解:(個人解法)轉換成二進制,而後直接用兩個指針比較。時間複雜度是 O(N)。

 

然而,solution給了 O(logN) 的作法。區別在於我存的是二進制的表示,人家存的是二進制表示中 1 的下標(index)。最後甚至於能夠用滾動數組優化,把存儲的矩陣給搞沒了。(厲害了。)

 

【869】Reordered Power of 2 (第二題 5分)

給了一個正整數 N, 咱們能夠把 N 的數字進行從新排列,搞出來一個新的 N (新的數不能以 0 開頭),問包括 N 在內的 N 的全部排列能不能有一個數是2的冪。

題解:(個人解法)我先把 N 字符串化,而後用 next_permutation 生成下一個排列,next_permutation() 這個方法有個小點要注意,使用前先對數組排序,才能生成全部的排列(在這裏WA了一次)。而後一開始我搞了一個set,裏面存了全部長度爲10位以及如下的全部的2的冪。用 next_permutaion 生成的數去 set 裏面找。 

 1 class Solution {
 2 public:
 3     bool reorderedPowerOf2(int N) {
 4         map<int, int> cnt;
 5         int t = N;
 6         while (t) {
 7             int r = t % 10;
 8             cnt[r]++;
 9             t /= 10;
10         }
11         long long x = 1;
12         int size = to_string(N).size();
13         while (to_string(x).size() < size) {
14             x*= 2;
15         }
16         while (to_string(x).size() == size) {
17             if (isSameWithN(x, cnt)) {
18                 return true;
19             }
20             x *= 2;
21         }
22         return false;
23     }
24     bool isSameWithN(int x, map<int, int> cnt) {
25         while (x) {
26             int r = x % 10;
27             if (cnt[r] > 0) {
28                 cnt[r]--;
29             } else {
30                 return false;
31             }
32             x /= 10;
33         }
34         return true;
35     }
36 };
View Code

 然而,solution裏面還有更優秀的解法。看完優秀解法我以爲我就是一個智障。咱們能夠先生成一個 2^x 這個數,而後判斷它和 N 是否是由相同的數字構成。(時間複雜度??how)

 

【870】Advantage Shuffle (第三題 7分)

 給了兩個長度同樣的數組 A 和 B,若是 A[i] > B[i],那麼說明 A[i] 比 B[i] 優秀。返回一個 A數組的排列,使得 A 比 B 優秀數最多。

題解:我是直接貪心了。就是先把 A 作個排序,而後對於 B 中的每一個元素用 upper_bound 求 A 中第一個比B[i] 大的元素,而後把這個元素從A刪除。剩下的 A 的元素填補空缺。

discuss中有個說法我更喜歡,就是說若是 A中有比 B[i] 大的元素,就應該使用第一個(最小的)比 B[i] 大的元素,若是沒有比 B[i] 大的元素,就是用 A 中最小的元素。

 1 class Solution {
 2 public:
 3     vector<int> advantageCount(vector<int>& A, vector<int>& B) {
 4         const int n = A.size();
 5         sort(A.begin(), A.end());
 6         vector<int> ans(n, 0), copyA = A;
 7         for (int i = 0; i < n; ++i) {
 8             auto iter = upper_bound(A.begin(), A.end(), B[i]);
 9             if (iter != A.end()) {
10                 int idx = distance(A.begin(), iter);
11                 ans[i] = *iter;
12                 A.erase(iter);
13             } else {
14                 ans[i] = -1;
15             }
16         }
17         auto iter = A.begin();
18         for (int i = 0; i < n; ++i) {
19             if (ans[i] == -1) {
20                 ans[i] = *iter;
21                 ++iter;
22             }
23         }
24         return ans;
25     }
26 };
View Code

 

 

【871】Minimum Number of Refueling Stops (第四題 9分)

 

 

 

Contest 94 (2018年10月27日,週六,題號 872-875)

連接:https://leetcode.com/contest/weekly-contest-94

比賽狀況記錄:這場整體來比較簡單,第一題是二叉樹的遍歷,第二題是模擬題(比賽的時候不知道哪裏錯了,無法AC),第三題是個二分答案,第四題我用dp作的,最後比賽完超時了不算提交。

【872】Leaf-Similar Trees (第一題 4分)

判斷兩棵二叉樹葉子結點的序列是否是同樣的。

題解:我是把兩棵樹的序列都求出來而後作比較的。

 1 /**
 2  * Definition for a binary tree node.
 3  * struct TreeNode {
 4  *     int val;
 5  *     TreeNode *left;
 6  *     TreeNode *right;
 7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 8  * };
 9  */
10 class Solution {
11 public:
12     bool leafSimilar(TreeNode* root1, TreeNode* root2) {
13         if (!root1 && !root2) { return true; }
14         if (!root1 || !root2) { return false; }
15         vector<int> leaf1, leaf2;
16         getLeafArray(root1, leaf1);
17         getLeafArray(root2, leaf2);
18         if (leaf1.size() != leaf2.size()) {
19             return false;
20         }
21         for (int i = 0; i < leaf1.size(); ++i) {
22             if (leaf1[i] != leaf2[i]) { return false; }
23         }
24         return true;
25     }
26     void getLeafArray(TreeNode* root, vector<int>& leaf) {
27         if (!root) { return; }
28         if (!root->left && !root->right) {
29             leaf.push_back(root->val);
30             return;
31         }
32         if (root->left) {
33             getLeafArray(root->left, leaf);
34         }
35         if (root->right) {
36             getLeafArray(root->right, leaf);
37         }
38         return;
39     }
40 };
View Code

 

【874】Walking Robot Simulation (第二題 4分)

一個機器人在無限大的地板上行走,給了一個 commands 數組,行走規則以下:

(1) commands[i] 等於 -2, 機器人向左轉90度

(2) commands[i] 等於 -1, 機器人向右轉90度

(3) commands[i] 屬於 [1, 9] , 機器人向前走 commands[i] 步

要求返回機器人全部走過的點中距離原點歐式距離最大的點,返回最大歐式距離的平方。

題解:審題是多麼的重要!!!!!這題我 WA 了好多遍都沒想明白爲啥,最後看了 solution 發現他是要求最大值!!!! 直接模擬,不說了。(讓我哭一下子)

  1 class Solution {
  2 public:
  3     int robotSim(vector<int>& commands, vector<vector<int>>& obstacles) {
  4         for (auto& p : obstacles) {
  5             stObs.insert(make_pair(p[0], p[1]));
  6         }
  7         pair<long long, long long> curPos(0, 0);
  8         dir curDir = north;
  9         
 10         vector<long long> simpleCommands;
 11         int idx = 0;
 12         while (idx < commands.size()) {
 13             if (commands[idx] < 0) {
 14                 simpleCommands.push_back(commands[idx]);
 15                 ++idx;
 16             } else {
 17                 long long step = 0;
 18                 while (idx < commands.size() && commands[idx] > 0) {
 19                     step += (long long)commands[idx];
 20                     ++idx;
 21                 }
 22                 simpleCommands.push_back(step);
 23             }
 24         }
 25         
 26         long long ans = 0;
 27         for (auto& com : simpleCommands) {
 28             if (com < 0) {
 29                 curDir = changeDir(curDir, com);
 30                 //printf("changeDir succ. curDir = %d \n", curDir);
 31             } else {
 32                 pair<long long, long long> newPos;
 33                 newPos = getNewPos(curPos, curDir, com);
 34                 //printf("getNewPos succ. dir = %d, curPos = (%d, %d), newPos = (%d, %d), len = %d\n", 
 35                       //curDir, curPos.first, curPos.second, newPos.first, newPos.second, com);
 36                 curPos = newPos;
 37                 ans = max(ans, curPos.first * curPos.first + curPos.second * curPos.second);
 38             }
 39         }
 40         return (int)ans;
 41     }
 42     
 43     //朝向轉換
 44     enum dir {
 45         north = 1,
 46         east = 2,
 47         south = 3,
 48         west = 4,
 49     };
 50     set<pair<int, int>> stObs;
 51     dir changeDir(dir NowDir, int turn) {
 52         if (NowDir == north) {
 53             return turn == -1 ? east : west;
 54         } else if (NowDir == east) {
 55             return turn == -1 ? south : north;
 56         } else if (NowDir == south) {
 57             return turn == -1 ? west : east;
 58         } else if (NowDir == west) {
 59             return turn == -1 ? north : south;
 60         }
 61     }
 62     pair<long long, long long> getNewPos(pair<long long, long long>& curPos, dir curDir, long long& len) {
 63         //north curPos.first += len
 64         //south curPos.first -= len
 65         //east curPos.second += len
 66         //west curPos.second -= len
 67         //printf("begin getNewPos: curPos = (%d, %d), curDir = %d, len = %d \n", curPos.first, curPos.second, curDir, len);
 68         if (curDir == north) {
 69             for (int s = 0; s < len; ++s) {
 70                 pair<long long, long long> newPos = curPos;
 71                 newPos.second++;
 72                 if (stObs.find(newPos) != stObs.end()) {
 73                     //printf("encounter an obs. pos(%d, %d) \n", newPos.first, newPos.second);
 74                     break;
 75                 }
 76                 curPos = newPos;
 77             }
 78         } else if (curDir == south) {
 79             for (int s = 0; s < len; ++s) {
 80                 pair<long long, long long> newPos = curPos;
 81                 newPos.second--;
 82                 if (stObs.find(newPos) != stObs.end()) {
 83                     //printf("encounter an obs. pos(%d, %d) \n", newPos.first, newPos.second);
 84                     break;
 85                 }
 86                 curPos = newPos;
 87             }
 88         } else if (curDir == east) {
 89             for (int s = 0; s < len; ++s) {
 90                 pair<long long, long long> newPos = curPos;
 91                 newPos.first++;
 92                 if (stObs.find(newPos) != stObs.end()) {
 93                     //printf("encounter an obs. pos(%d, %d) \n", newPos.first, newPos.second);
 94                     break;
 95                 }
 96                 curPos = newPos;
 97             }
 98         } else if (curDir == west) {
 99             for (int s = 0; s < len; ++s) {
100                 pair<long long, long long> newPos = curPos;
101                 newPos.first--;
102                 if (stObs.find(newPos) != stObs.end()) {
103                     //printf("encounter an obs. pos(%d, %d) \n", newPos.first, newPos.second);
104                     break;
105                 }
106                 curPos = newPos;
107             }
108         }
109         return curPos;
110     }
111 };
View Code

 

【875】Koko Eating Bananas (第三題 6分)(二分答案)

有 N 堆香蕉,每一堆裏面有 piles[i] 個香蕉,Koko只能在守衛離開的時候吃香蕉,已知守衛要離開 H 小時,假設Koko吃香蕉的速度是 K 個香蕉每小時, 每一個小時內,Koko 只能吃一堆香蕉(即便香蕉堆裏面的香蕉不足 K 個,他也不能去別的香蕉堆裏面吃),Koko想在 H 小時裏面把全部的香蕉吃完,問 K 最小是多少。

題解:首先思考了一個特殊的case,就是當 一共有 H 堆香蕉 而守衛剛好離開 H 小時的時候,K 的最小值就是 max(piles[i])。由於他必須一個小時剛好吃一堆,才能把全部香蕉吃完。而後咱們經過思考一下能夠發現, 當 香蕉的堆數 N <H 的時候,K 的最小值也能夠變小,由於時間變長了,koko能夠 2個小時只吃一堆香蕉。因此 咱們能夠推測出 K 是有範圍的, (1 <= K <= max(piles[i]))。

爲了方便,咱們先把 piles[] 排個序。而後用二分答案的方法求 K 的最小值。二分的條件就是 koko 能不能在當前時間內吃完全部香蕉。

 1 class Solution {
 2 public:
 3     int minEatingSpeed(vector<int>& piles, int H) {
 4         const int n = piles.size();
 5         sort(piles.begin(), piles.end());
 6         if (H == n) {
 7             return piles.back();
 8         }
 9         // 1 <= K <= piles[n-1];
10         int left = 1, right = piles[n-1] + 1;
11         while (left < right) {
12             int mid = (left + right) / 2;
13             if (!canFinish(piles, H, mid)) { //吃不完
14                 left = mid + 1;
15             } else {
16                 right = mid;
17             }
18         }
19         int K = left;
20         return K;
21     }
22     bool canFinish(vector<int>& piles, int H, int K) {
23         int cntH = 0;
24         for (auto p : piles) {
25             cntH += p % K ? p / K + 1 : p / K; 
26         }
27         return cntH <= H;
28     }
29 };
View Code

  

【873】Length of Longest Fibonacci Subsequence (第四題 6分)

這個題最後作出來了。。。

 

Contest 95(2018年10月29日,週一,題號 876-879)

連接:https://leetcode.com/contest/weekly-contest-95

比賽狀況記錄:作出了兩道題,第三題TLE了,第四題似曾相識然而沒思路。ranking: 1078/3750。

【876】Middle of the Linked List   (第一題 3分)

給了一個鏈表,返回中間結點,若是是奇數長度的鏈表就返回中間那個,若是是偶數長度的鏈表就返回中間靠後的那個。

題解:two pointers 一個往前走一步,一個往前走兩步。當走的快的結點走到 nullptr 的時候,走的慢的結點正好走到中間。一次 AC 了。 

 1 /**
 2  * Definition for singly-linked list.
 3  * struct ListNode {
 4  *     int val;
 5  *     ListNode *next;
 6  *     ListNode(int x) : val(x), next(NULL) {}
 7  * };
 8  */
 9 class Solution {
10 public:
11     ListNode* middleNode(ListNode* head) {
12         if (!head) {return head;}
13         ListNode *slow = head, *fast = head;
14         while (fast && fast->next) {
15             if (fast->next) {
16                 fast = fast->next->next;
17                 slow = slow->next;
18             }
19         }
20         return slow;
21     }
22 };
View Code

 

【877】Stone Game (第二題 5分)(這題相似的題也作過了,可是仍是不會作,須要往回看)

有 N 堆 (N 是偶數) 石子排成一排,每堆石子有 piles[i] 個,有玩家 1 和玩家 2 。遊戲每輪只能從這排石子的最左或者最右兩邊拿一堆,最後誰的石子總數(石子總數是奇數,因此不會平手)最多誰就是贏家。假設兩個玩家都絕頂聰明(play optimally),玩家 1 先開始遊戲,問玩家 1 最後能不能贏,玩家 1 能贏返回 true, 否則返回false。

題解:這題仍是不會啊,要 go die 了啊。作過的相似的題目有 lc 486 Predict the Winner; 464 Can I Win; 這種模式仍是掌握不了。(dp; Minimax)。也能夠參考 《程序員代碼面試指南》Chp4. P233

《程序員代碼面試指南》原題(排成一條線的紙牌博弈問題):給定一個數組 arr,表明數值不一樣的紙牌排成一條線。玩家 A 和玩家 B 依次拿走每張紙牌,規定玩家 A 先拿,玩家 B 後拿,可是每一個玩家每次只能拿走最左或者最右的紙牌,玩家 A 和玩家 B 都絕頂聰明。請返回最後獲勝者的分數。

抄一遍題解:定義遞歸函數 f(i, j), 表示若是 arr[i, j] 這個排列上的紙牌(石子)被絕頂聰明的人先拿,最終能得到什麼分數。定義遞歸函數 s(i, j),表示若是 arr[i,j] 這個排列上的紙牌(石子)被絕頂聰明的人後拿,最終能得到什麼分數。

咱們首先來分析 f(i, j),具體過程以下:(1)當 i == j (即 a[i..j] )上只剩一張紙牌。那麼固然會被先拿紙牌的人拿走, 因此返回 arr[i]。 (2)若是 i != j,那麼當前拿紙牌的人有兩個選擇,要麼拿走 arr[i], 要麼拿走 arr[j]。若是拿走了 arr[i],那麼排列剩下了 arr[i+1 ..j],對當前的玩家來講,面對 arr[i+1 .. j] 排列的紙牌,他成了後拿的人,因此他後續能得到的分數是 s(i+1, j)。若是這我的拿走了 a[j],那麼排列將剩下 arr[i .. j+1]。對當前的玩家來講,面對 arr[i .. j-1] 排列的紙牌,他成了後拿的人,因此後續他能得到的分數是 s(i, j+1)。做爲絕頂聰明的人,必然會在兩種決策中選擇最優的。因此返回 max{arr[i]+s(i+1, j), arr[j]+s(i, j-1)}。

而後來分析 s(i, j),具體過程以下:(1) 若是 i == j (即 a[i..j]) 上只剩一張紙牌。做爲後拿紙牌的人必然什麼也的不到,返回 0。 (2) 若是 i != j,根據函數 s(i, j) 的定義,玩家的對手會先拿紙牌。對手要麼拿走 arr[i],要麼拿走 arr[j]。若是對手拿走 arr[i],那麼排列將剩下 arr[i+1.. j],而後輪到玩家拿。若是對手拿走 arr[j],那麼排列將剩下 arr[i.. j-1],而後輪到玩家拿。對手也是決定聰明的人,因此,必然會把最差的狀況留給玩家。因此返回 min{f(i+1, j), f(i, j-1)}。

暴力遞歸代碼以下 win1: 在暴力遞歸的方法中,遞歸函數一共有 N 層,而且是 f 和 s 交替出現的。

///等待補充中 

 1 class Solution {
 2 public:
 3     bool stoneGame(vector<int>& piles) {
 4         const int n = piles.size();
 5         int summ = 0;
 6         for (auto p : piles) {
 7             summ += p;
 8         }
 9         int score = f(piles, 0, n-1);  //玩家 1 的分數
10         int score2 = s(piles, 0, n-1); //玩家 2 的分數
11         return score + score > summ ? true : false;
12     }
13     int f(vector<int>& piles, int i, int j) {
14         if (i == j) {
15             return piles[i];
16         }
17         return max(piles[i] + s(piles, i+1, j), piles[j] + s(piles, i, j-1));
18     }
19     int s(vector<int>& piles, int i, int j) {
20         if (i == j) {
21             return 0;
22         }
23         return min(f(piles, i+1, j), f(piles, i, j-1));
24     }
25 };
View Code

下面介紹 dp 方法,假如數組 arr 的長度爲 N,生成兩個大小爲 N * N的矩陣 f 和 s,f[i][j] 表示 f(i,j) 的返回值,s[i][j] 返回 s(i, j) 的返回值。規定一下計算方向便可。時間複雜度是  O(N^2),空間複雜度是 O(N^2)。

 1 class Solution {
 2 public:
 3     bool stoneGame(vector<int>& piles) {
 4         const int n = piles.size();
 5         int summ = 0;
 6         for (auto p : piles) {
 7             summ += p;
 8         }
 9         vector<vector<int>> f(n, vector<int>(n, 0));
10         vector<vector<int>> s = f;
11         for (int j = 0; j < n; ++j) {
12             f[j][j] = piles[j];
13             for (int i = j - 1;i >= 0; --i) {
14                 f[i][j] = max(piles[i] + s[i+1][j], piles[j] + s[i][j-1]);
15                 s[i][j] = min(f[i+1][j], f[i][j-1]);
16             } 
17         }
18         int score = f[0][n-1];
19         return score + score > summ ? true : false;
20     }
21 };
View Code 

 

【878】Nth Magical Number (第三題 7分)(數學題,求循環節)

 A positive integer is magical if it is divisible by either A or B. Return the N-th magical number.  Since the answer may be very large, return it modulo 10^9 + 7.

Example 1:

Input: N = 1, A = 2, B = 3 Output: 2 

Example 2:

Input: N = 4, A = 2, B = 3 Output: 6 
Note:
  1. 1 <= N <= 10^9
  2. 2 <= A <= 40000
  3. 2 <= B <= 40000

題解:這道題我一開始想的是醜數那題,按照那個方法作了直接tle。由於 N 太大了,O(N)的算法確定是tle了。而後看了solution,答案說先求 A, B 的 lcm, 咱們發現一個 lcm 裏面包含了這樣 step 個數 (step = (L/A) + (L/B) - 1) ,而後求循環節 times = N / step ; r = N % lcm; 所求的第 N 個數就至關於 lcm走了 times,而後剩餘 r 個。(而後你知道怎麼搞了...)。而後暴力求剩下的 r 個的時候,注意求數的時候必定不要 取 MOD,否則要涼涼。

 1 #define MOD 1000000007
 2 class Solution {
 3 public:
 4     int nthMagicalNumber(int N, int A, int B) {
 5         long long L = getLcm(A, B);
 6         long long step = (L / A) + (L / B) - 1;
 7         long long times = N / step;
 8         long long r = N % step;
 9         long long base = (times * L) % MOD;
10         long long ans = 0;
11         if (r == 0) {
12             ans = base;
13         } else {
14             long long numA = A, numB = B;
15             int cnt = 0;
16             long long number = 0;
17             while (cnt < r) {
18                 if (numA <= numB) {
19                     number = numA;
20                     //這裏必定不要取 mod,當有一個數取了mod以後變成一個很小的數,後面就無法繼續比較了,它只會一直加這個比較小的數
21                     numA += A;  //numA = (numA + A) % MOD;  
22                 } else if (numA > numB) {
23                     number = numB;
24                     //這裏必定不要取 mod,當有一個數取了mod以後變成一個很小的數,後面就無法繼續比較了,它只會一直加這個比較小的數
25                     numB += B;   //numB = (numB + B) % MOD;
26                 }
27                 cnt++;
28             }
29             ans = (base + number) % MOD;
30         }
31         return (int)ans;
32     }
33     long long getLcm(int A, int B) {
34         if (A < B) {
35             swap(A, B);
36         }
37         int gcd = getGcd(A, B);
38         long long mul = (long long)A * B;
39         return  mul / gcd;
40     }
41     int getGcd(int A, int B) { // A max, B min
42         if (B == 0) {return A;}
43         while (B) {
44             int r = A % B;
45             A = B;
46             B = r;
47         }
48         return A;
49     }
50 };
View Code

 discuss 裏面竟然還有人用二分,有空學習一下。

 

【879】Profitable Schemes (第四題 7分)

 

 

 

Contest 96(2018年11月1日,週四,題號 880-883)

比賽狀況記錄: 前三題都作出來了,前兩題比較穩,第三題不怎麼會寫,最後直接尾遞歸搞過了。第四題啊,圖論啊,不會作哇。吐血。ranking:199/3916

【883】Projection Area of 3D Shapes (第一題 4分)

題意就是把小方塊累起來的一個建築物求三面的投影數,返回三面投影的總數。

題解:就是單純的模擬。沒啥說的。

 1 class Solution {
 2 public:
 3     int projectionArea(vector<vector<int>>& grid) {
 4         const int n = grid.size(), m = grid[0].size();
 5         //cal xy;
 6         int xy = 0;
 7         for (int i = 0; i < n; ++i) {
 8             for (int j = 0; j < m; ++j) {
 9                 if (grid[i][j]) {
10                     xy++;
11                 }
12             }
13         }
14         //cal xz (max of col)
15         int xz = 0;
16         for (int j = 0; j < m; ++j) {
17             int maxx = grid[0][j];
18             for (int i = 1; i < n; ++i) {
19                 maxx = max(maxx, grid[i][j]);
20             }
21             xz += maxx;
22         }
23         // cal yz (max of row) {
24         int yz = 0;
25         for (int i = 0; i < n; ++i) {
26             int maxx = grid[i][0];
27             for (int j = 1; j < m; ++j) {
28                 maxx = max(maxx, grid[i][j]);
29             }
30             yz += maxx;
31         }
32         int ans = xy + xz + yz;
33         return ans;
34     }
35 };
View Code

 

【881】Boats to Save People (第二題 5分)

題意:給了一個people數組,和一個 limit 整數。people[i] 表明第 i 我的的體重,每一個小船最多能夠載兩我的,總重量不能超過 limit。問最少要幾艘小船才能裝完全部人。(題目保證確定有解,沒有人的體重超過 limit)

題解:貪心。先把 people 數組排序,而後最小體重的人和最大致重的人一組,看能不能一艘船,不能的話,就把大致重的人換成一個稍微小體重的人。剩下的沒有上船的大致重的人都是本身一艘船。時間複雜度是O(nlogn)。

 1 class Solution {
 2 public:
 3     int numRescueBoats(vector<int>& people, int limit) {
 4         const int n = people.size();
 5         sort(people.begin(), people.end());
 6         vector<int> boats(n, -1); //boats[i] means the ith people int boats[i]
 7         int p1 = 0, p2 = n-1;
 8         int tot = 0;
 9         while (p1 < p2) {
10             if (people[p1] + people[p2] <= limit) {
11                 boats[p1] = boats[p2] = tot;
12                 tot++;
13                 p1++, p2--;
14             } else if (people[p1] + people[p2] > limit) {
15                 --p2;
16             }
17         }
18         int left = 0;
19         for (auto& p : boats) {
20             if (p == -1) {
21                 left++;
22             }
23         }
24         return left + tot;
25     }
26 };
View Code

 

【880】Decoded String at Index (第三題 6分)

題意:給了一個編碼過的字符串,若是字符串中的字符是字母的話,那這個字母就是tape中的,若是這個字符是數字 d 的話,就要把前面全部的字符串重複 d 次(共 d 次)。返回整個字符串中下標是 K 的字符。

 

  1. 2 <= S.length <= 100
  2. S will only contain lowercase letters and digits 2 through 9.
  3. S starts with a letter.
  4. 1 <= K <= 10^9
  5. The decoded string is guaranteed to have less than 2^63 letters。

題解:比賽的時候我這題是作出來的,可是代碼寫的太挫了,直接尾遞歸了。  K 那麼大確定不能生成那麼大的字符串,因而我想的是找出每一個循環節,而後每次能夠縮小 K。

 1 class Solution {
 2 public:
 3     string decodeAtIndex(string S, int K) {
 4         vector<long long> repeat;
 5         stringstream ss;
 6         ss << S;
 7         long long len = 0;
 8         string use = "";
 9         char c;
10         while (ss) {
11             ss >> c;
12             use += c;
13             if (isdigit(c)) {
14                 len = len * (c - '0');
15                 repeat.push_back(len);
16                 if (len >= K) {break;}
17             } else {
18                 ++len;
19                 if (len == K) {
20                     string temp = "";
21                     temp += c;
22                     return temp;
23                 }
24             }
25         }
26         const int n = repeat.size();        
27         long long preLen = repeat.back() / (c - '0');
28         int left = K % preLen;
29         if (left == 0) {
30             string ans = "";
31             for (int k = use.size(); k >= 0; --k) {
32                 if (use[k] >= 'a' && use[k] <= 'z') {
33                     ans += use[k];
34                     break;
35                 }
36             }
37             return ans;
38         }
39         return decodeAtIndex(S, left);
40     }
41 };
比賽代碼--挫

看了solution:

 

【882】Reachable Nodes In Subdivided Graph (第四題 7分)

 

 

Contest 97(2018年11月3日,週六,題號 884-887)

連接:

比賽狀況記錄:

 

 

 

 

Contest 98(2018年11月5日,週一,題號 888-891)

連接:https://leetcode.com/contest/weekly-contest-98

比賽狀況記錄:作出來了三道題,結果:3/4,ranking:295/2883。看到第四題的時候還有45分鐘,有思路,小數據能過,大數據過不了。(爲啥大數據過不了我很懵逼)

【888】Fair Candy Swap(第一題 3分)

有兩我的小A和小B,每一個人都有一個數組做爲他們的糖果堆(小A和小B的堆數可能不同),小A和小B只能交換一堆糖果,返回交換哪堆能讓小A和小B的糖果數相等。題目保證有答案。

題解:先求總數而後求一半,這就是最後他們每一個人的糖果數。而後枚舉小A的一堆,看能不能找到小B中對應的那堆,使得兩我的糖果數量相等。

 1 class Solution {
 2 public:
 3     vector<int> fairCandySwap(vector<int>& A, vector<int>& B) {
 4         long long summA = 0, summB = 0;
 5         int sizeA = A.size(), sizeB = B.size();
 6         for (int i = 0; i < sizeA; ++i) {
 7             summA += (long long)A[i];
 8         }
 9         for (int i = 0; i < sizeB; ++i) {
10             summB += (long long)B[i];
11         }
12         long long tot = summA + summB, half = tot / 2;
13         sort(A.begin(), A.end()), sort(B.begin(), B.end());
14         vector<int> ans;
15         int diff = half - summA;
16         for (int i = 0; i < sizeA; ++i) {
17             int target = A[i] + diff;
18             auto iter = lower_bound(B.begin(), B.end(), target);
19             if (iter != B.end() && *iter == target) {
20                 ans.push_back(A[i]);
21                 ans.push_back(target);
22                 break;
23             }
24         }
25         return ans;
26     }
27 };
View Code

 

【890】Find and Replace Pattern (第二題 5分)

給了一堆words和一個pattern,找出符合pattern形式的全部words返回。

Input: words = ["abc","deq","mee","aqq","dkd","ccc"], pattern = "abb"
Output: ["mee","aqq"]
Explanation: "mee" matches the pattern because there is a permutation {a -> m, b -> e, ...}. 
"ccc" does not match the pattern because {a -> c, b -> c, ...} is not a permutation,
since a and b map to the same letter.

題解:用個 map 記錄對應關係,沒有對應關係的話加上,可是有一點須要注意,例子中的數據,abc是不能對應abb(pattern)的,因此還須要一個set記錄pattern中的字符是否被別的字符對應了。

 1 class Solution {
 2 public:
 3     vector<string> findAndReplacePattern(vector<string>& words, string pattern) {
 4         const int n = words.size(), size = pattern.size();
 5         vector<string> ans;
 6         if (n == 0) {return ans;}
 7         for (auto& word : words) {
 8             bool inAns = true;
 9             map<char, char> mp; // word -> pattern
10             set<char> usedPattern;
11             for (int i = 0; i < size; ++i) {
12                 if (mp.find(word[i]) == mp.end()) {
13                     if (usedPattern.find(pattern[i]) == usedPattern.end()) {
14                         mp[word[i]] = pattern[i];
15                         usedPattern.insert(pattern[i]);
16                     } else { //conflict
17                         inAns = false;
18                         break;
19                     }
20                 } else {
21                     if (mp[word[i]] != pattern[i]) {
22                         inAns = false;
23                         break;
24                     }
25                 }
26             }
27             if (inAns) {
28                 ans.push_back(word);
29             }
30         }
31         return ans;
32     }
33 };
View Code

 

【889】Construct Binary Tree from Preorder and Postorder Traversal (第三題 5分)

給了二叉樹的先序遍歷和後序遍歷,重建二叉樹。

題解:我還稍微想了一下子,主要是靠什麼區分左子樹的pre,post和右子樹的pre,post。經過觀察發現,pre的第二個元素必定是左子樹的根,post中左子樹根以前的元素都屬於左子樹。因此就能區分左右子樹的pre和post數組了。而後遞歸重建就好了。

 1 /**
 2  * Definition for a binary tree node.
 3  * struct TreeNode {
 4  *     int val;
 5  *     TreeNode *left;
 6  *     TreeNode *right;
 7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 8  * };
 9  */
10 class Solution {
11 public:
12     TreeNode* constructFromPrePost(vector<int>& pre, vector<int>& post) {
13         const int n = pre.size();
14         if (n == 0) {return nullptr;}
15         if (n == 1) {
16             TreeNode* root = new TreeNode(pre[0]);
17             return root;
18         }
19         int rootVal = pre[0], leftRootVal = pre[1];
20         int idxPostLeftRootVal = 0;
21         for (idxPostLeftRootVal = 0; idxPostLeftRootVal < post.size(); ++idxPostLeftRootVal) {
22             if (leftRootVal == post[idxPostLeftRootVal]) {break;}
23         }
24         int leftPreSize = idxPostLeftRootVal + 1;
25         TreeNode* root = new TreeNode(rootVal);
26         vector<int> leftPre(pre.begin() + 1, pre.begin() + 1 + leftPreSize);
27         vector<int> leftPost(post.begin(), post.begin() + leftPreSize);
28         vector<int> rightPre(pre.begin() + 1 + leftPreSize, pre.end());
29         vector<int> rightPost(post.begin() + leftPreSize, post.end() - 1);
30         root->left = constructFromPrePost(leftPre, leftPost);
31         root->right = constructFromPrePost(rightPre, rightPost);
32         return root;
33     }
34 };
View Code

 

【891】Sum of Subsequence Widths (第四題 7分)

 

Contest 99(2018年11月6日,週二凌晨,題號 892-895)

連接:https://leetcode.com/contest/weekly-contest-99

比賽狀況記錄:第一題有點卡住,後來仍是解決了。30分鐘作了三道題,第四題放棄了。總之我這周要狂攻hard題。結果: 3/4, ranking:286/3153

【892】Surface Area of 3D Shapes(第一題 4分)

給了一個 N * N 的grid,咱們想放 1 * 1 * 1 的 cubes,v = grid[i][j] 至關於在座標(i, j)處放了一個高度 v 的塔。返回所搭建模型的表面積。

Example 1:
Input: [[2]]
Output: 10
Example 2: Input: [[1,2],[3,4]] Output: 34
Example 3: Input: [[1,0],[0,2]] Output: 16
Example 4: Input: [[1,1,1],[1,0,1],[1,1,1]] Output: 32

Example 5: Input: [[2,2,2],[2,1,2],[2,2,2]] Output: 46

題解:我原本想用每行每列的最大值直接看成側面而後乘以2的,結果我發現那個模型可能裏面有個凹坑。好比 example 4.和 example 5. 後來就一行一行,一列一列的求差,求側面積。

 1 class Solution {
 2 public:
 3     int surfaceArea(vector<vector<int>>& grid) {
 4         const int n = grid.size();
 5         int front = 0, side = 0, top = 0;
 6         for (int i = 0; i < n; ++i) {
 7             side += grid[i][0];
 8             for (int j = 0; j < n; ++j) {
 9                 if (grid[i][j]) { top++; }
10                 if (j > 0) {
11                     side += abs(grid[i][j] - grid[i][j-1]);
12                 }
13             }
14             side += grid[i][n-1];
15         }
16         for (int j = 0; j < n; ++j) {
17             front += grid[0][j];
18             for (int i = 1; i < n; ++i) {
19                 front += abs(grid[i][j] - grid[i-1][j]);
20             }
21             front += grid[n-1][j];
22         }
23         //printf("side = %d, front = %d \n", side, front);
24         int ret = top * 2 + side + front;
25         return ret;
26     }
27 };
View Code

 

【893】Groups of Special-Equivalent Strings (第二題 4分)

字符串 S 等價於 字符串T的定義是 S字符串的奇數和奇數下標元素間任意交換,偶數和偶數下標之間任意交換,最後能夠變換成 T。給了一個字符串數組,題目保證數組裏面的字符串長度都是同樣的。問這個數組能分紅幾個小組,每一個小組裏面的字符串都是等價的。

題解:我是設計了一種數據結構 set<pair<string, string>> 用這個 pair 結構來存每一個單詞的奇數下標組成的字符串,偶數下標組成的字符串(須要排序),結果就是 set 的大小。

 1 class Solution {
 2 public:
 3     int numSpecialEquivGroups(vector<string>& A) {
 4         int ret = 0;
 5         const int n = A.size(), m = A[0].size();
 6         set<pair<string, string>> st; //odd, even
 7         for (auto& w : A) {
 8             string odd = "", even = "";
 9             for (int i = 0; i < m; ++i) {
10                 if (i & 1) {
11                     odd += string(1, w[i]);
12                 } else {
13                     even += string(1, w[i]);
14                 }
15             }
16             sort(odd.begin(), odd.end());
17             sort(even.begin(), even.end());
18             st.insert(make_pair(odd, even));
19         }
20         ret = st.size();
21         return ret;
22     }
23 };
View Code

 

【894】All Possible Full Binary Trees (第三題 6分)

一個滿二叉樹的定義是一個結點要麼左右兩個兒子,要麼它是葉子結點。給了一個數字 N, 要求返回 N 個結點的滿二叉樹的全部形態。

題解:這棵滿二叉樹的左兒子的大小多是 {1, 3, 5 .. n - 2}, 右兒子的大小多是 {n - 2, n - 4, .. ,1}。咱們能夠遞歸的生成左兒子和右兒子的集合,而後左兒子裏選一個,右兒子裏面選一個,再加上根節點組成一棵二叉樹。

 1 /**
 2  * Definition for a binary tree node.
 3  * struct TreeNode {
 4  *     int val;
 5  *     TreeNode *left;
 6  *     TreeNode *right;
 7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 8  * };
 9  */
10 class Solution {
11 public:
12     vector<TreeNode*> allPossibleFBT(int N) {
13         vector<TreeNode*> ret;
14         if (N == 0) {return ret;}
15         if (N == 1) {
16             TreeNode* root = new TreeNode(0);
17             ret.push_back(root);
18             return ret;
19         }
20         
21         for (int leftSize = 1; leftSize < N - 1; leftSize = leftSize + 2) {
22             int rightSize = N - 1 - leftSize;
23             vector<TreeNode*> left = allPossibleFBT(leftSize);
24             vector<TreeNode*> right = allPossibleFBT(rightSize);
25             for (auto l : left) {
26                 for (auto r : right) {
27                     TreeNode* root = new TreeNode(0);
28                     root->left = l; 
29                     root->right = r;
30                     ret.push_back(root);
31                 }
32             }
33         }
34         return ret;
35     }
36     
37 };
View Code

 

【895】Maximum Frequency Stack (第四題 8分)

相關文章
相關標籤/搜索