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分)

  • 相关阅读:
    Effective Java 19 Use interfaces only to define types
    Effective Java 18 Prefer interfaces to abstract classes
    Effective Java 17 Design and document for inheritance or else prohibit it
    Effective Java 16 Favor composition over inheritance
    Effective Java 15 Minimize mutability
    Effective Java 14 In public classes, use accessor methods, not public fields
    Effective Java 13 Minimize the accessibility of classes and members
    Effective Java 12 Consider implementing Comparable
    sencha touch SortableList 的使用
    sencha touch dataview 中添加 button 等复杂布局并添加监听事件
  • 原文地址:https://www.cnblogs.com/zhangwanying/p/9843611.html
Copyright © 2011-2022 走看看