連接: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 };
【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 };
【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 };
【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 };
連接: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 };
【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 };
【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 };
【864】Shortest Path to Get All Keys (第四題 9分)
連接: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 };
然而,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 };
【871】Minimum Number of Refueling Stops (第四題 9分)
連接: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 };
【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 };
【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 };
【873】Length of Longest Fibonacci Subsequence (第四題 6分)
這個題最後作出來了。。。
連接: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 };
【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 };
下面介紹 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 };
【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 <= N <= 10^9
2 <= A <= 40000
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 };
discuss 裏面竟然還有人用二分,有空學習一下。
【879】Profitable Schemes (第四題 7分)
比賽狀況記錄: 前三題都作出來了,前兩題比較穩,第三題不怎麼會寫,最後直接尾遞歸搞過了。第四題啊,圖論啊,不會作哇。吐血。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 };
【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 };
【880】Decoded String at Index (第三題 6分)
題意:給了一個編碼過的字符串,若是字符串中的字符是字母的話,那這個字母就是tape中的,若是這個字符是數字 d 的話,就要把前面全部的字符串重複 d 次(共 d 次)。返回整個字符串中下標是 K 的字符。
2 <= S.length <= 100
S
will only contain lowercase letters and digits 2
through 9
.S
starts with a letter.1 <= K <= 10^9
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分)
連接:
比賽狀況記錄:
連接: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 };
【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 };
【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 };
【891】Sum of Subsequence Widths (第四題 7分)
連接: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 };
【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 };
【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 };
【895】Maximum Frequency Stack (第四題 8分)