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

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

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

模拟比赛情况记录:第一题柠檬摊的那题6分钟AC,然后是第二题树的距离K的结点那题比较久,大概写了30分钟,第三题翻转矩阵那题第一次提交错误了,列的优化方法思路错了,WA。后来比赛时间到了才改过来。最后一题最短子数组的和比K大的这题不会做。

【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 的个数少就翻转。

 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日学习)(第四题)

给了一个数组 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分)

 

posted @ 2018-10-24 15:10  zhangwanying  阅读(507)  评论(0编辑  收藏  举报