【Leetcode周赛】从contest-41开始。(一般是10个contest写一篇文章)
Contest 41 ()(题号)
Contest 42 ()(题号)
Contest 43 ()(题号)
Contest 44 (2018年12月6日,周四上午)(题号653—656)
链接:https://leetcode.com/contest/leetcode-weekly-contest-44
比赛情况记录:就做出来两题,第三题不难,然而就是在算坐标的时候卡住了。orz。结果:2/4,ranking:637/2272。第四题没看题,第三题搞得心情不好了orz。
【653】Two Sum IV - Input is a BST(第一题 3分)
输入是一棵 BST, 问能不能在这棵 BST 里面找到两个结点,使得两个结点的和等于 target。
题解:我是先 dfs 成了一个有序数组,然后 2 pointers 做的。还可以 dfs 成一个 map。
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 findTarget(TreeNode* root, int k) { 13 dfs(root); 14 const int n = nums.size(); 15 int p1 = 0, p2 = n - 1; 16 while (p1 < p2) { 17 int summ = nums[p1] + nums[p2]; 18 if (summ == k) { return true; } 19 if (summ < k) { p1++; } 20 else { p2--; } 21 } 22 return false; 23 } 24 void dfs(TreeNode* root) { 25 if (!root) {return;} 26 dfs(root->left); 27 nums.push_back(root->val); 28 dfs(root->right); 29 return; 30 } 31 vector<int> nums; 32 };
【654】Maximum Binary Tree(第二题 5分)
给了一个 unique 的数组,没有重复数字。生成 maximum binary tree。生成规则:根是数组最大的元素,根左边的子数组做左子树,根右边的子数组做右子树。所有子树也满足这些性质。
题解:直接递归生成。
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* constructMaximumBinaryTree(vector<int>& nums) { 13 const int n = nums.size(); 14 if (n == 0) {return nullptr;} 15 int maxValue = nums[0], maxIdx = 0; 16 for (int i = 1; i < n; ++i) { 17 if (nums[i] > maxValue) { 18 maxIdx = i; 19 maxValue = nums[i]; 20 } 21 } 22 TreeNode* root = new TreeNode(maxValue); 23 vector<int> LeftSon(nums.begin(), nums.begin()+maxIdx); 24 vector<int> RightSon(nums.begin() + maxIdx + 1, nums.end()); 25 root->left = constructMaximumBinaryTree(LeftSon); 26 root->right = constructMaximumBinaryTree(RightSon); 27 return root; 28 } 29 };
【655】Print Binary Tree(第三题 7分)
打印二叉树。打印规则见例子。
Example 1: Input: 1 / 2 Output: [["", "1", ""], ["2", "", ""]] Example 2: Input: 1 / \ 2 3 \ 4 Output: [["", "", "", "1", "", "", ""], ["", "2", "", "", "", "3", ""], ["", "", "4", "", "", "", ""]] Example 3: Input: 1 / \ 2 5 / 3 / 4 Output: [["", "", "", "", "", "", "", "1", "", "", "", "", "", "", ""] ["", "", "", "2", "", "", "", "", "", "", "", "5", "", "", ""] ["", "3", "", "", "", "", "", "", "", "", "", "", "", "", ""] ["4", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]]
题解:我在比赛的时候卡住了,算列坐标的时候算不出来系列。返回的数组是 n * m 大小, n 是二叉树的高度,m = 2^n - 1。然后我们递归的生成每棵子树。列坐标其实是 (l + r)/2。
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<vector<string>> printTree(TreeNode* root) { 13 if (!root) { 14 return vector<vector<string>>(); 15 } 16 globalHeight = getHeight(root); 17 const int cols = pow(2, globalHeight) - 1; 18 vector<vector<string>> ret(globalHeight, vector<string>(cols, "")); 19 printTree(root, ret, globalHeight, 0, cols); 20 return ret; 21 } 22 void printTree(TreeNode* root, vector<vector<string>>& ret, int height, int l, int r) { 23 if (!root) {return;} 24 int mid = (l + r) / 2; 25 printTree(root->left, ret, height - 1, l, mid); 26 ret[globalHeight - height][mid] = to_string(root->val); 27 printTree(root->right, ret, height - 1, mid + 1, r); 28 return; 29 } 30 31 int getHeight(TreeNode* root) { 32 if (!root) {return 0;} 33 return max(getHeight(root->left), getHeight(root->right)) + 1; 34 } 35 int globalHeight = 0; 36 };
【656】Coin Path(第四题 9分)
Contest 45 (2018年12月4日,周二下午)(题号657-660)
链接:https://leetcode.com/contest/leetcode-weekly-contest-45/
比赛情况记录:3/4,ranking:298/2292。 第三题我预估是勉强卡线过的,应该可以更加优化。第四题一点想法都没有,怀疑是不是要把含有9的数都生成出来。
【657】Robot Return to Origin(第一题 3分)
给了一个字符串,由 "L", "R", "U", "D" 组成,代表机器人走的方向,一个字符代表一步,机器人起点在原点,问它能不能最后回到原点。
题解:签到题。分别数出这四个字符的个数,判断上下,左右能不能完全抵消。
1 class Solution { 2 public: 3 bool judgeCircle(string moves) { 4 int cntL = 0, cntR = 0, cntU = 0, cntD = 0; 5 for (auto& c : moves) { 6 if (c == 'L') {cntL++;} 7 if (c == 'R') {cntR++;} 8 if (c == 'U') {cntU++;} 9 if (c == 'D') {cntD++;} 10 } 11 return (cntL == cntR) && (cntU == cntD) ? true : false; 12 } 13 };
【658】Find K Closest Elements(第二题 6分)
给了一个有序递增数组,和两个数字 x 和 k。我们的目标是在数组中找到 k 个离 x 最近的数,如果答案有多个,就返回小的那个。从小到大返回这 k 个数。
题解:我先二分找到 x 的 upper_bound,然后分类处理的。如果 iter 在最左或者最右,就返回前面或者后面 k 个数。如果在中间,就 2 pointers。
1 class Solution { 2 public: 3 vector<int> findClosestElements(vector<int>& arr, int k, int x) { 4 const int n = arr.size(); 5 auto iter = upper_bound(arr.begin(), arr.end(), x); 6 if (iter == arr.end()) { 7 vector<int> ret(arr.end() - k, arr.end()); 8 return ret; 9 } else if (iter == arr.begin()) { 10 vector<int> ret(arr.begin(), arr.begin() + k); 11 return ret; 12 } 13 int p2 = distance(arr.begin(), iter), p1 = p2 - 1; 14 vector<int> ret(k); 15 for (int i = 0; i < k; ++i) { 16 int number = -1; 17 if (p1 >= 0 && p2 < n) { 18 if (abs(arr[p1] - x) <= abs(arr[p2] - x)) { 19 number = arr[p1--]; 20 } else { 21 number = arr[p2++]; 22 } 23 } else if (p1 >= 0) { 24 number = arr[p1--]; 25 } else if (p2 < n) { 26 number = arr[p2++]; 27 } 28 ret[i] = number; 29 } 30 sort(ret.begin(), ret.end()); 31 return ret; 32 } 33 };
应该可以更快,我这个解法只 beats 了 53%+。
【659】Split Array into Consecutive Subsequences(第三题 8分)
给了一个有序 int 数组arr,数组里面可能有重复元素,问能不能把这个 int 数组分割成几个连续的整数序列。(每个整数序列的元素个数必须大于3个)。能的话返回 true, 不能的话返回 false。
题解:我的解法只beats了 1%。我感觉是压线过的。我设计了一个结构 vector<pair<int, int>> segs 。里面每个元素 seg 存储整数序列的最左和最右值。如果只是一个元素 number,那么 p(number, number) 。然后对于 arr 中的每个元素 number,依次想往 segs 中的元素里面靠,如果有多个 candidate 可以靠的话,就做个类似于负载均衡这样的东西,不要让一个 seg 太长,力求让每个 seg 的长度都平均。(为啥呢,比如 arr = [1, 2, 3, 3 ,4, 5] , 我期待的结果是 [1, 3], [3, 5],但是如果不做这个负载均衡的话,就可能出现 [1, 5], [3, 3] 的结果。)靠上了之后,就看能不能合并 seg,如果没靠上的话,就这个 number 自己生成一个 seg,加入 segs。
1 class Solution { 2 public: 3 bool isPossible(vector<int>& nums) { 4 const int n = nums.size(); 5 if (n < 3) {return false;} 6 vector<pair<int, int>> segs(1, make_pair(nums[0], nums[0])); 7 for (int i = 1; i < n; ++i) { 8 int number = nums[i]; 9 int mark = -1, sizeMark = n; 10 for (int j = 0; j < segs.size(); ++j) { 11 const int sizeJ = segs[j].second - segs[j].first + 1; 12 if (number == segs[j].first - 1) { 13 //segs[j].first = number; 14 if (mark == -1) { 15 mark = j; 16 } else if (sizeMark > sizeJ) { 17 sizeMark = sizeJ; 18 mark = j; 19 } 20 } else if (number == segs[j].second + 1) { 21 //segs[j].second = number; 22 if (mark == -1) { 23 mark = j; 24 } else if (sizeMark > sizeJ){ 25 sizeMark = sizeJ; 26 mark = j; 27 } 28 } 29 } 30 //printf("number = %d, mark = %d \n", number, mark); 31 if (mark == -1) { 32 segs.push_back(make_pair(number, number)); 33 continue; 34 } else { 35 if (number == segs[mark].first - 1) { 36 segs[mark].first = number; 37 } else { 38 segs[mark].second = number; 39 } 40 int del = -1; 41 if (number == segs[mark].first) { 42 for (int k = 0; k < segs.size(); ++k) { 43 if (k == mark) {continue;} 44 if (number == segs[k].second + 1) { 45 //printf("combine. %d, segs[%d] && segs[%d] \n", __LINE__ ,k, mark); 46 segs[k].second = segs[mark].second; //[k, mark] 47 del = mark; 48 break; 49 } 50 } 51 } else if (number == segs[mark].second) { 52 for (int k = 0; k < segs.size(); ++k) { 53 if (k == mark) {continue;} 54 if (number == segs[k].first - 1) { 55 //printf("combine. %d, segs[%d] && segs[%d] \n", __LINE__ ,mark, k); 56 segs[mark].second = segs[k].second; //[mark, k] 57 del = k; 58 break; 59 } 60 } 61 } 62 if (del != -1) { 63 segs.erase(segs.begin() + del); 64 } 65 } 66 } 67 for (auto p : segs) { 68 //printf("(%d, %d) \n", p.first, p.second); 69 if (p.second - p.first < 2) {return false;} 70 } 71 return true; 72 } 73 };
那么其实应该还有更优秀的解法,等我学习一下。
【660】Remove 9(第四题 9分)
Contest 46 (2018年12月31日,周一下午)(题号661-664)
链接:https://leetcode.com/contest/leetcode-weekly-contest-46/
【661】Image Smoother(第一题 3分)
一个图像的平滑处理器,每个像素点的值等于它周围八个点和它自己的平均值。求平滑后的图像。
题解:无
1 class Solution { 2 public: 3 vector<vector<int>> imageSmoother(vector<vector<int>>& M) { 4 vector<vector<int>> ret(M); 5 const int n = M.size(), m = M[0].size(); 6 for (int i = 0; i < n; ++i) { 7 for (int j = 0; j < m; ++j) { 8 int summ = M[i][j], div = 1; 9 for (int k = 0; k < 8; ++k) { 10 int newx = i + dirx[k], newy = j + diry[k]; 11 if (newx >= 0 && newx < n && newy >= 0 && newy < m) { 12 div++; 13 summ += M[newx][newy]; 14 } 15 } 16 ret[i][j] = summ / div; 17 } 18 } 19 return ret; 20 } 21 int dirx[8] = {-1, 0, 1, 0, -1, -1, 1, 1}; 22 int diry[8] = {0, -1, 0, 1, -1, 1, -1, 1}; 23 };
【662】Maximum Width of Binary Tree(第二题 6分)
返回一棵二叉树的最宽距离。最宽距离的定义是同一层从最左边的第一个非空的结点到最右边的非空结点的结点数(中间可以包含空结点)。
题解: 我用了2个deque做的层级遍历。dq1用来记录当前层的结点,dq2用来记录下一层的结点。在遍历dq2之前先把它头部和尾部所有空结点删除。然后再遍历。
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 int widthOfBinaryTree(TreeNode* root) { 13 if (!root) { return 0; } 14 deque<TreeNode*> que, que2; 15 que.push_back(root); 16 int res = 0; 17 while(!que.empty()) { 18 while (!que.empty() && que.front() == nullptr) { 19 que.pop_front(); 20 } 21 while (!que.empty() && que.back() == nullptr) { 22 que.pop_back(); 23 } 24 res = max(res, (int)que.size()); 25 while (!que.empty()) { 26 TreeNode* cur = que.front(); que.pop_front(); 27 if (cur == nullptr) { 28 que2.push_back(nullptr); 29 que2.push_back(nullptr); 30 continue; 31 } 32 que2.push_back(cur->left); 33 que2.push_back(cur->right); 34 } 35 swap(que, que2); 36 } 37 return res; 38 } 39 };
【663】Equal Tree Partition(第三题 7分)
【664】Strange Printer (第四题 9分)