zoukankan      html  css  js  c++  java
  • 【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("
    ");
    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 
    ", 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 
    ", 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 
    ", 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
    ", 
     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 
    ", 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) 
    ", 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) 
    ", 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) 
    ", 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) 
    ", 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 
    ", 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分)

  • 相关阅读:
    C#_WinForm接收命令行参数
    SQLite不支持的SQL语法总结
    Thirft框架介绍
    jquery获取复选框的值
    REST构架风格介绍:状态表述转移
    RESTful HTTP的实践infoQ
    C#如何在webBrowser1控件通过TagName,Name查找元素(没有ID时)遍历窗体元素
    Html TO Ubb and Ubb TO Html
    SQL 位运算
    Memcached真的过时了吗?【转帖】
  • 原文地址:https://www.cnblogs.com/zhangwanying/p/9843611.html
Copyright © 2011-2022 走看看