首页 > 其他 > 详细

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

时间:2019-02-27 21:08:32      阅读:163      评论:0      收藏:0      [点我收藏+]

Contest 111 (题号941~944)(2019年1月19日,补充题解,主要是943题)

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

【941】Valid Mountain Array(第一题 3分)

判断一个数组是不是 Mountain 数组。 Mountain 数组的定义是

题解

Delete Columns to Make Sorted(第二题 4分)

DI String Match(第三题 5分)

【943】Find the Shortest Superstring(第四题 8分)

Given an array A of strings, find any smallest string that contains each string in A as a substring.

We may assume that no string in A is substring of another string in A.

Example 1:
Input: ["alex","loves","leetcode"]
Output: "alexlovesleetcode"
Explanation: All permutations of "alex","loves","leetcode" would also be accepted.
Example 2:
Input: ["catg","ctaagt","gcta","ttca","atgcatc"]
Output: "gctaagttcatgcatc"
 
Note:
1 <= A.length <= 12
1 <= A[i].length <= 20

题解:本题可以看成旅行商问题,用状态压缩的动态规划来解。我们先给每个单词都标号,然后从word1到word2重合之后,word2长出来的长度就是图的权重。比如 word1 = abcd, word2 = bcdfsd, g[word1][word2] = 3.

然后我们想走过每一个单词,使得图的总权重最小。这个就是旅行商问题的定义。我们用一个二进制 11110111, 表示除了第三个单词不在,其他七个单词都存在。这个就是状态压缩。(用一个二进制表示一个set中的元素是否存在)

《挑战设计程序竞赛》3.4.1

假设我们现在已经访问过顶点的集合是S,当前所在的顶点为 v, 用 dp[S][v]表示从v出发访问剩余的所有顶点,最终回到顶点0的路径的权重总和的最小值。由于从 v 出发可以移动到任意的一个节点 u 不属于 S,因此有下面的递推式。

dp[V][0] = 0;

dp[S][v] = min{dp[S U {u}][u] + d(v, u) | u 不属于 S }

技术分享图片
 1 class Solution {
 2 public:
 3     const int MAX = 12;
 4     string shortestSuperstring(vector<string>& A) {
 5         const int n = A.size();
 6         vector<vector<int>> g = initGraph(A);
 7         vector<vector<int>> dp(1 << MAX, vector<int>(n, INT_MAX));
 8         int path[1 << MAX][MAX] = {INT_MAX};
 9         int minLen = INT_MAX, last = -1;
10         for (int S = 0; S < 1 << n; ++S) {
11             for (int j = 0; j < n; ++j) {
12                 if ((S & (1 << j)) > 0) {  //一定要加括号,不然先算 (1 << j) > 0 再算 位运算
13                     int prev = S - (1 << j);
14                     if (prev == 0) {
15                         dp[S][j] = A[j].size();
16                     } else {
17                         for (int k = 0; k < n; ++k) {
18                             if (dp[prev][k] < INT_MAX && dp[prev][k] + g[k][j] < dp[S][j]) {
19                                 dp[S][j] = min(dp[prev][k] + g[k][j], dp[S][j]);
20                                 path[S][j] = k;
21                             }
22                         }
23                     }
24                 }
25                 if (S == ((1 << n) - 1) && dp[S][j] < minLen) {
26                     minLen = dp[S][j];
27                     last = j;
28                 }
29             }
30         }
31         // build string.
32         string ret = "";
33         int index = last, pre = last, state = (1 << n) -1;
34         vector<int> seq(n);
35         for (int i = n-1; i >= 0; --i) {
36             seq[i] = index;
37             pre = path[state][index];
38             state = state - (1 << index);
39             // printf ("index = %d, state = %d, pre = %d \n", index, state, pre);
40             index = pre;
41         }
42         
43         ret = A[seq[0]];
44         for (int i = 1; i < n; ++i) {
45             string str = A[seq[i]];
46             ret += str.substr(str.size() - g[seq[i-1]][seq[i]]);    
47         }
48         return ret;
49     }
50     vector<vector<int>> initGraph(vector<string>& A) {
51         const int n = A.size();
52         vector<vector<int>> g(n, vector<int>(n, 0));
53         for (int i = 0; i < A.size(); ++i) {
54             for (int j = i; j < A.size(); ++j) {
55                 g[i][j] = cal(A[i], A[j]);
56                 g[j][i] = cal(A[j], A[i]);
57             }
58         }
59         return g;
60     }
61     int cal(string s1, string s2) { //A[u] = s1, A[v] = s2
62         const int n1 = s1.size(), n2 = s2.size();
63         int ret = n2;
64         for (int k = 1; k < n1; ++k) {
65             string sub1 = s1.substr(k); // len = n1 - k
66             string sub2 = s2.substr(0, n1-k); // len = n1 - k;
67             if (sub1 == sub2) {
68                 ret = min(ret, n2 - n1 + k);
69                 break;
70             }
71         }
72         return ret;
73     }
74     void print(vector<vector<int>>& g) {
75         const int n = g.size();
76         const int m = g[0].size();
77         for (int i = 0; i < n; ++i) {
78             for (int j = 0; j < m; ++j) {
79                 printf("%d ", g[i][j]);
80             }
81             printf("\n");
82         }
83     }
84 };
View Code

 

Contest 112(2018年11月25日)(题号945~948)

比赛情况记录:这场有点像是贪心专题了orz,结果:1/4,ranking:1383/3195,第一题懵逼的原因是 5-3=3?==。这场真的没有一题难题,然后就是不会做。这就比较尴尬了。

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

【945】Minimum Increment to Make Array Unique(第一题 5分)

题意是给了一个数组有重复数字,目标是把数组中的元素都变成 unique 的,游戏规则是移动一步可以把一个数字加一。问最少移动几步能把所有数字unique化。

题解:先排序,然后按照排序的数字递增,缺几个就加几。

技术分享图片
 1 class Solution {
 2 public:
 3     int minIncrementForUnique(vector<int>& A) {
 4         sort(A.begin(), A.end());
 5         const int n = A.size();
 6         int res = 0;
 7         for (int i = 1; i < n; ++i) {
 8             if (A[i] > A[i-1]) {continue;}
 9             int newAi = A[i-1]+1;
10             res += newAi - A[i];
11             A[i] = newAi;
12         }
13         return res;
14     }
15 };
View Code

 

【946】Validate Stack Sequences(第二题 6分)(我没记错的话这题应该是剑指offer原题)

给了两个 distinct 的序列,问一个作为栈的 push 序列的话,另外一个是否能作为 pop 序列。

题解:直接模拟栈的行为。

技术分享图片
 1 class Solution {
 2 public:
 3     bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
 4         const int n = pushed.size();
 5         stack<int> stk;
 6         int p1 = 0, p2 = 0;
 7         while (p1 < n && p2 < n) {
 8             while (stk.empty() || stk.top() != popped[p2]) {
 9                 stk.push(pushed[p1++]);
10             }
11             while (!stk.empty() && stk.top() == popped[p2]) {
12                 stk.pop();
13                 ++p2;
14             }
15         }
16         while (!stk.empty() && stk.top() == popped[p2]) {
17             stk.pop();
18             ++p2;
19         }
20         return stk.empty();
21     }
22 };
View Code

 

【947】Most Stones Removed with Same Row or Column(第三题 6分)(2019年1月30日,谷歌tag复习)

 

 

【948】Bag of Tokens(第四题 6分)(2018年12月9日,算法群每日一题,补充的周赛解题报告)

题意是给了一个tokens的数组,和一个原始的power P,游戏规则如下:(1)用 tokens[i] 的 power 可以换 1 point; (2) 用 1 point 也可以换 tokens[i] 的power。问最多能换多少 point。

题解:greedy + 2 pointers。排序之后用2 pointers 两遍夹逼。前面的pointer用来换point(一直往前直到当前的power换不起point了), 后面的pointer用来换power。

技术分享图片
 1 class Solution {
 2 public:
 3     int bagOfTokensScore(vector<int>& tokens, int P) {
 4         const int n = tokens.size();
 5         sort(tokens.begin(), tokens.end()); //1. sort
 6         int points = 0, ret = 0;
 7         //2 .2 pointers, boundary
 8         int p1 = 0, p2 = n - 1;
 9         while (p1 <= p2) {
10             int preP1 = p1, preP2 = p2;
11             while (p1 <= p2 && P >= tokens[p1]) {
12                 points += 1;
13                 P -= tokens[p1++];
14             } 
15             ret = max(points, ret);
16             if (p1 <= p2 && points >= 1) {
17                 points -= 1;
18                 P += tokens[p2--];
19             }
20             if (p1 == preP1 && p2 == preP2) {
21                 break;
22             }
23         }
24         return ret;
25     }
26 };
View Code

 

Contest 113 (2018年12月2日)(题号949~952)

比赛情况记录:结果:3/4, ranking: 708/3549。起床晚了,第一题手残调试点成提交,懵逼的WA了三次。第二题跟 symmetric tree 那个很像。第三题跟前几周周赛的第四题很像。第四题他们说是线性筛法求素数。

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

【949】Largest Time for Given Digits(第一题 4分)

给了一个数组里面四个整数(0-9),返回这个数组能生成的最大时间表示 HH:MM。

题解:暴力生成所有的排列,然后判断是否符合时间的定义,然后用ret变量标记最大的字符串。(时间相关的类似题:lc 681)

技术分享图片
 1 class Solution {
 2 public:
 3     string largestTimeFromDigits(vector<int>& A) {
 4         sort(A.begin(), A.end());
 5         if (A[0] >= 3) {return "";}
 6         string ret = "";
 7         do {
 8             string str = string(1, A[0] + 0) + string(1, A[1] + 0) + ":" + string(1, A[2] + 0) + string(1, A[3] + 0);
 9             if (isValid(str)) {
10                 if (str > ret) {
11                     ret = str;
12                 }
13             }
14         } while(next_permutation(A.begin(), A.end()));
15         return ret;
16     }
17     bool isValid(string str) {
18         if (str[0] > 2) { return false;}
19         if (str[0] == 2 && str[1] >= 4) { return false; }
20         if (str[3] >= 6) { return false;}
21         return true;
22     }
23 };
View Code

 

【951】Flip Equivalent Binary Trees(第二题 5分)

For a binary tree T, we can define a flip operation as follows: choose any node, and swap the left and right child subtrees.

A binary tree X is flip equivalent to a binary tree Y if and only if we can make X equal to Y after some number of flip operations.

Write a function that determines whether two binary trees are flip equivalent.  The trees are given by root nodes root1 and root2.

技术分享图片

题解:我先判断有没有根,有根但是值不相等的话,就返回false,递归判断 root1 的左儿子和 root2 的左儿子 以及 root1 的右儿子和 root2 的右儿子 是不是 FlipEqui,如果是直接返回yes。否则递归判断 root1 的右儿子和 root2 的左儿子 以及 root1 的左儿子和 root2 的右儿子 是不是 FlipEqui,是的话,返回yes。都不行就返回false。(类似题:lc 101)

技术分享图片
 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 flipEquiv(TreeNode* root1, TreeNode* root2) {
13         if (!root1 && !root2) {return true;}
14         if (!root1 || !root2) {return false;}
15         if (root1->val != root2->val) {return false;}
16         bool res1 = flipEquiv(root1->left, root2->left) && flipEquiv(root1->right, root2->right);
17         if (res1) {
18             return res1;
19         } 
20         bool res2 = flipEquiv(root1->left, root2->right) && flipEquiv(root1->right, root2->left);
21         if (res2) {
22             return res2;
23         }
24         return false;
25     }
26 };
View Code

 

【950】Reveal Cards In Increasing Order(第三题 5分)

我们有一个 N 张的 unique 纸牌,我们希望得到一个序列,按照下面步骤操作之后,从这个序列弹出的序列是完全排好序的。

(1)弹出最上面一张纸牌 A1。

(2)如果 A1 下面有纸牌 A2,把 A2 放到这叠纸牌的最下方。

依次循环做(1)(2)操作。

Example 1:
Input: [17,13,11,2,3,5,7]
Output: [2,13,3,11,5,17,7]
Explanation: 
We get the deck in the order [17,13,11,2,3,5,7] (this order doesn‘t matter), and reorder it.
After reordering, the deck starts as [2,13,3,11,5,17,7], where 2 is the top of the deck.
We reveal 2, and move 13 to the bottom.  The deck is now [3,11,5,17,7,13].
We reveal 3, and move 11 to the bottom.  The deck is now [5,17,7,13,11].
We reveal 5, and move 17 to the bottom.  The deck is now [7,13,11,17].
We reveal 7, and move 13 to the bottom.  The deck is now [11,17,13].
We reveal 11, and move 17 to the bottom.  The deck is now [13,17].
We reveal 13, and move 17 to the bottom.  The deck is now [17].
We reveal 17.
Since all the cards revealed are in increasing order, the answer is correct.

题解:先把数组排序好了之后,从小到大依次隔空插入。

技术分享图片
 1 class Solution {
 2 public:
 3     vector<int> deckRevealedIncreasing(vector<int>& deck) {
 4         const int n = deck.size();
 5         sort(deck.begin(), deck.end());
 6         vector<int> ret(n, -1);
 7         int gap = 1, k = 0;
 8         while (k < n) {
 9             for (int i = 0; i < n; ++i) {
10                 if (ret[i] != -1) {continue;}
11                 if (gap) {
12                     ret[i] = deck[k];
13                     ++k;
14                     gap = 0;
15                     if (k >= n) {break;}
16                 } else {
17                     if (ret[i] == -1) {gap = 1;}
18                 }  
19             }
20         }
21         return ret;
22     }
23 };
View Code

 

【952】Largest Component Size by Common Factor (第四题 8分)

 

Contest 114(2018年12月9日)(题号953-956)

比赛情况记录:本周一直比较萎靡,唉,结果:2/4,ranking: 696 / 3198,我认为第三题第四题都不难,然而实现上有困难,肯定是我的问题了。

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

【953】Verifying an Alien Dictionary(第一题 4分)

有一种外星文字也包含 ‘a’ 到 ‘z‘ 26个字母,只不过字母顺序不一样罢了。给了一堆 words,判断这些 words 是不是按照外星字典顺序排列的。

题解:我用 unordered_map 存储了外星字母对应英文字母的关系,然后把每一个 word 转换成英文单词,看这些单词是否符合字典顺序。

技术分享图片
 1 class Solution {
 2 public:
 3     bool isAlienSorted(vector<string>& words, string order) {
 4         //1. map relationship
 5         unordered_map<char, char> mp;
 6         for (int i = 0; i < 26; ++i) {
 7             mp[order[i]] = i + a;
 8         }
 9         //2. change word
10         vector<string> inputs = words;
11         for (auto& w : inputs) {
12             for (auto& c : w) {
13                 c = mp[c];
14             }
15         }
16         //3. check order
17         for (int i = 1; i < inputs.size(); ++i) {
18             if (inputs[i] < inputs[i-1]) {
19                 return false;
20             }
21         }
22         return true;
23     }
24 };
View Code

 

【954】Array of Doubled Pairs(第二题 5分)

 

【955】Delete Columns to Make Sorted II(第三题 6分)

【956】Tallest Billboard(第四题 8分)

 

 

Contest 115(2018年12月16日)(题号957-960)

比赛情况记录:本周比赛马马虎虎吧,第四题不会做比较尴尬。结果: 2/4,ranking: 490/3055。第三题看了题真是没啥想法。第四题是个LIS的变种题(把一列看成一个元素,自己实现比较大小)。

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

【958】Check Completeness of a Binary Tree(第一题 5分)

检查一棵树是不是完全二叉树。

题解:第一题有稍微有点卡住了。有两种检测方法,都不是那么的直观。第一种是 dfs,判断是不是左右子树都是完全二叉树,然后判断左子树高度最多比右子树高度大一。第二种是 bfs,判断方法是

(1)如果当前结点有右孩子但是没有左孩子,那么直接返回false。

(2)如果当前结点不是左右孩子都有,那么后面的结点都必须是叶子结点。

技术分享图片
 1 /**
 2  * Definition for a binary tree node.
 3  * struct TreeNode {
 4  *     int val;
 5  *     TreeNode *left;
 6  *     TreeNode *right;
 7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 8  * };
 9  */
10 class Solution {
11 public:
12     bool isCompleteTree(TreeNode* root) {
13         if (!root) {return true;}
14         queue<TreeNode*> que;
15         que.push(root);
16         bool mark = false;
17         while (!que.empty()) {
18             int size = que.size();
19             for (int i = 0; i < size; ++i) {
20                 TreeNode* cur = que.front(); que.pop();
21                 if (mark && (cur->left || cur->right)) {
22                     return false;
23                 }
24                 if (cur->left) {
25                     que.push(cur->left);
26                 }
27                 if (cur->right) {
28                     que.push(cur->right);
29                 }
30                 if (cur->left && !cur->right || !cur->left && !cur->right) {
31                     mark = true;
32                 }
33                 if (cur->right && !cur->left) {
34                     return false;
35                 }
36             }
37         }
38         return true;
39     }
40 };
bfs

 

【957】Prison Cells After N Days(第二题 6分)

有一个数组里面有 8 个0/1元素, 分别代表8个囚室,0代表囚室为空,1代表囚室有人。每天囚室的人员分布都在变化。变化规则就是如下两条:

  • If a cell has two adjacent neighbors that are both occupied or both vacant, then the cell becomes occupied.
  • Otherwise, it becomes vacant.

给了 Day 0 的囚室分布,问第 N 天的囚室分布。1 <= N <= 10^9

题解:这题肯定是有循环节的。我们可以注意到第一个 cell 和最后一个 cell 肯定从第一天开始就都是 0 了,因为他们就没有两个邻居。然后中间的 6个 cell,它们要么是 0 要么是 1。所以循环节最多也就是 2^6 = 64 个排列。我们用个数组记录每个vector代表的二进制数。然后我们找循环节就行了。

技术分享图片
 1 class Solution {
 2 public:
 3     vector<int> prisonAfterNDays(vector<int>& cells, int N) {
 4         int number = vector2Int(cells);
 5         vector<int> array(256, -1);
 6         vector<int> nCells = cells;  
 7         int day = 0;
 8         do {
 9             array[day++] = number;
10             number = transNextDay(nCells);
11             if (day == N + 1) {
12                 break;
13             }
14         } while (find(array.begin(), array.end(), number) == array.end());
15         if (day == N + 1) {
16             vector<int> ret = getVector(array[N]);
17             return ret;
18         }
19         auto iter = find(array.begin(), array.end(), number);
20         const int startDay = distance(array.begin(), iter);
21         const int cycle = day - startDay;
22         int idx = ((N - startDay) % cycle);
23         vector<int> ret = getVector(array[startDay + idx]);
24         return ret;
25     }
26     int vector2Int(const vector<int>& nums) {
27         int pow = 1, ret = 0;
28         for (int i = 0; i < 8; ++i) {
29             ret += pow * nums[i];
30             pow *= 2;
31         }
32         return ret;
33     }
34     int transNextDay(vector<int>& nCells) {
35         vector<int> newCells(8, 0);
36         for (int i = 1; i < 8 -1; ++i) {
37             if (nCells[i-1] ^ nCells[i+1] == 0) {
38                 newCells[i] = 1;
39             } 
40         }
41         int ret = vector2Int(newCells);
42         nCells = newCells;
43         return ret;
44     }
45     vector<int> getVector(int num) {
46         vector<int> ret(8, 0);
47         for (int i = 0; i < 8; ++i) {
48             ret[i] = num % 2;
49             num /= 2;
50         }
51         return ret;
52     }
53 };
View Code

 

【959】Regions Cut By Slashes(第三题 7分)

 

 

【960】Delete Columns to Make Sorted III(第四题 7分)

给了一个字符串数组 A,A[i] 表示一个字符串,我们要从字符矩阵A中删除某几列字符,使得每个字符串都是符合字母序的 (every element (row) in lexicographicorder)。问最少删除几列。

题解:这个题目有点像是 LIS,但是比赛的时候没想出来,我想的是每行都 LIS,然后求出 min(LIS) = x,在[1, x]中二分求最大的k。但是其实不是这样想的,这样暴力解复杂度太高,又难写。本题事实上应该把每一列都看成 LIS 的一个元素,然后我们自己定义元素的大小比较关系就行了。时间复杂度是 O(m*m*n)

技术分享图片
 1 class Solution {
 2 public:
 3     int minDeletionSize(vector<string>& A) {
 4         const int n = A.size(), m = A[0].size();
 5         vector<int> dp(m, 1);
 6         int maxLen = 1;
 7         for (int i = m - 2; i >= 0; --i) {
 8             for (int j = i + 1; j < m; ++j) {
 9                 bool found = false;
10                 for (int k = 0; k < n; ++k) {
11                     if (A[k][i] > A[k][j]) {
12                         found = true;
13                         break;
14                     }
15                 }
16                 if (!found) {
17                     dp[i] = max(dp[i], dp[j] + 1);
18                     maxLen = max(maxLen, dp[i]);
19                 }
20             }
21         }
22         return m - maxLen;
23     }
24 };
View Code

 

Contest 116(2018年12月23日)(题号961-964)

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

比赛情况记录:结果: 1/4,ranking: 1745/2965. 这两天我也不知道怎么了,锻炼练不下去,题目不想做,唉。希望只是一时状态不好而已。

【961】N-Repeated Element in Size 2N Array(第一题 2分)

 

【962】Maximum Width Ramp(第二题 5分)

给了一个数组 A,想找一对 tuple (i, j),满足 i < j && A[i] <= A[j]. 找到gap间距最大的 i, j, 返回 max(gap) 。

题解:看了lee215的解答,他说用 decreasing stack。其实我到现在都没有彻底get到这个点在哪里。吐血了。

技术分享图片
 1 class Solution {
 2 public:
 3     int maxWidthRamp(vector<int>& A) {
 4         const int n = A.size();
 5         stack<int> stk;
 6         for (int i = 0; i < n; ++i) {
 7             if (stk.empty() || A[stk.top()] > A[i]) {
 8                 stk.push(i);
 9             }
10         }
11         int ret = 0;
12         for (int i = n-1; i > 0; --i) {
13             while (!stk.empty() && A[i] >= A[stk.top()]) {
14                 printf("i = %d, stk.top() = %d, A[i] = %d, A[stk.top()] = %d\n", i, stk.top(), A[i], A[stk.top()]);
15                 ret = max(i - stk.top(), ret);
16                 stk.pop();
17             }
18         }
19         return ret;
20     }
21 };
View Code

 

【963】Minimum Area Rectangle II(第三题 5分)

 

【964】Least Operators to Express Number (第四题 9分)

 

Contest 117(2018年12月30日)(题号965-968)

比赛情况记录:今天早上爬起来看群主mock interview,然后回去睡了一个回笼觉,结果就实在起不来了。所以这次是比赛之后马上开的virtual,virtual结果: 3/4,ranking:495/2770.

【965】Univalued Binary Tree(第一题 3分)

给了一棵二叉树判断整棵数是不是所有结点都是一个值。保证至少有一个根结点。

题解:dfs 或者 bfs 随你喜欢。

技术分享图片
 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 isUnivalTree(TreeNode* root) {
13         if (!root) {return true;}   
14         const int value = root->val;
15         queue<TreeNode*> que;
16         que.push(root);
17         bool ret = true;
18         while (!que.empty()) {
19             auto cur = que.front(); que.pop();
20             if (cur->val != value) {
21                 ret = false;
22                 break;
23             }
24             if (cur->left) {
25                 que.push(cur->left);
26             }
27             if (cur->right) {
28                 que.push(cur->right);
29             }
30         }
31         return ret;
32     }
33     
34 };
View Code

 

【967】Numbers With Same Consecutive Differences(第二题 5分)

返回所有长度为 N 的非负整数,相邻两个数位的差的绝对值是 K。前缀 0 的数是非法的,所以不要包含前缀 0 的数,比如 01,0 本身是合法的。

题解:dfs。我写的比较唠叨了,这题还可以更简洁。简洁版本有待补充。

技术分享图片
 1 class Solution {
 2 public:
 3     vector<int> numsSameConsecDiff(int N, int K) {
 4         vector<int> ret;
 5         if (K == 0) {
 6             string strMul = string(N, 1);
 7             const int mul = stoi(strMul);
 8             for (int i = 1; i <= 9; ++i) {
 9                 int number = i * mul;
10                 ret.push_back(number);
11             }
12             if (N == 1) {
13                 ret.push_back(0);
14             }
15             return ret;
16         }
17         for (int i = 1; i <= 9; ++i) {
18             string strNum = to_string(i);
19             dfs(strNum, N - 1, K, ret);
20         }
21         if (N == 1) {
22             ret.push_back(0);
23         }
24         return ret;
25     }
26     void dfs(string& strNum, int leftSize, const int K, vector<int>& ret) {
27         if (leftSize == 0) {
28             ret.push_back(stoi(strNum));
29             return;
30         }
31         int back = strNum.back() - 0;
32         if (back + K <= 9) {
33             string strLastDigit = to_string(back + K);
34             string strNew = strNum + strLastDigit;
35             dfs(strNew, leftSize - 1, K, ret);
36         }
37         if (back - K >= 0) {
38             string strLastDigit = to_string(back - K);
39             string strNew = strNum + strLastDigit;
40             dfs(strNew, leftSize - 1, K, ret);
41         }
42         return;
43     }
44     
45 };
View Code

 

【966】Vowel Spellchecker(第三题 6分)

给了一个单词表和一大堆 query,每次 query 给一个单词,问这个单词能不能通过给出的规则变成单词表里面的词。能的话,返回第一个单词表里面对应的单词。

规则一。query的单词本身就在单词表中。

规则二。query的单词通过更改大小写字母变换成单词表中单词。

规则三。query的单词通过更换元音字母变换成单词表中单词。(这个匹配大小写不敏感)

规则优先级按照一二三递减。

题解:我这题一开始超时了,后来翻了一下群记录,原来要把元音化成通配符,类似pattern那种感觉。

技术分享图片
 1 class Solution {
 2 public:
 3     vector<string> spellchecker(vector<string>& wordlist, vector<string>& queries) {
 4         set<string> stWord(wordlist.begin(), wordlist.end());
 5         const int n = queries.size();
 6         vector<string> ret(n, "");
 7         set<char> stTemp = {a, e, i, o, u};
 8         stVowel = stTemp;
 9         //build map
10         for (int idx = 0; idx < wordlist.size(); ++idx) {
11             string strNew = str2Lower(wordlist[idx]);
12             if (mp.find(strNew) == mp.end()) {
13                 mp[strNew] = idx;
14             }
15             string s2 = str2Pattern(strNew);
16             if (mpVowels.find(s2) == mpVowels.end()) {
17                 mpVowels[s2] = idx;
18             }
19         }
20         for (int i = 0; i < n; ++i) {
21             string w = queries[i];
22             if (stWord.find(w) != stWord.end()) { //rule1
23                 ret[i] = w;
24             } else if (mp.find(str2Lower(w)) != mp.end()) { //rule2
25                 int idx = mp[str2Lower(w)];
26                 ret[i] = wordlist[idx];
27             } else { //rule3
28                 int idx = checkRule3(w);
29                 if (idx == -1) { continue; }
30                 ret[i] = wordlist[idx];
31             } 
32         }
33         return  ret;
34     }
35     unordered_map<string, int> mp, mpVowels;
36     set<char> stVowel;
37     inline string str2Lower(string str) {
38         string strNew = str;
39         for (int i = 0; i < strNew.size(); ++i) {
40             if (isupper(strNew[i])) {
41                 strNew[i] = tolower(strNew[i]);
42             }
43         }
44         return strNew;
45     }
46     inline string str2Pattern(string str) {
47         string strNew = str;
48         for (auto & c: strNew) {
49             if (stVowel.find(c) != stVowel.end()) {
50                 c = *;
51             }
52         }
53         return strNew;
54     }
55     int checkRule3 (string str) {
56         string strNew = str2Lower(str);
57         strNew = str2Pattern(strNew);
58         int ret = -1;
59         if (mpVowels.find(strNew) != mpVowels.end()) {
60             ret = mpVowels[strNew];
61         }
62         return ret;
63     }
64 };
View Code

 

【968】Binary Tree Cameras(第四题 8分)

 

Contest 118(2019年1月6日)(题号969-972)

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

总结:rank 730/3587, 结果:2/4。 具体比赛的时候的想法已经忘没了,尴尬。噢,第二题我本来是想出来的,结果手残了还没看出来。

【970】Powerful Integers(第一题 3分)

给了两个非负整数,x 和 y, 以及一个数 bound,求表达式 x^i + y^j 中所有小于等于 bound 的值,用数组的形式返回。其中 i >= 0, j >= 0。

题解:直接暴力,注意 x = 1 和 y = 1 的时候怎么办。不要写死循环了。

技术分享图片
 1 class Solution {
 2 public:
 3     vector<int> powerfulIntegers(int x, int y, int bound) {
 4         int curx = 1, cury = 1;
 5         set<int> ret;
 6         for (int i = 0; curx + cury <= bound; ++i) {
 7             for (int j = 0; curx + cury <= bound; ++j) {
 8                 if (curx + cury <= bound) {
 9                     ret.insert(curx + cury);
10                 } 
11                 cury *= y;
12                 if (cury * y == cury) {
13                     break;
14                 }
15             }
16             if (curx * x == curx) {
17                 break;
18             }
19             curx *= x;
20             cury = 1;
21         }
22         vector<int> ans;
23         for (auto s : ret) {
24             ans.push_back(s);
25         }
26         return ans;
27     }
28 };
View Code

 

【969】Pancake Sorting(第二题 5分)

煎饼排序,一次煎饼翻转的操作如下:我们可以选一个正整数 k,然后翻转前 k 个煎饼。输入是一个 A 数组,代表煎饼的大小,输出是一个 k 的数组,代表经过这个 k 数组的操作之后,A数组可以变成有序的。(k 的长度不超过 10 * A.size())

题解:我们可以考虑每次操作都使得一个煎饼放在最下方。可以这么操作,选出没有排序的数组中的最大煎饼,然后翻转一次,把最大的煎饼翻转到第一个位置,然后翻转整个没有排序的数组,把最大的煎饼从第一个位置换到最后一个位置。这样产生的 K 数组的大小是 2N。

技术分享图片
 1 class Solution {
 2 public:
 3     vector<int> pancakeSort(vector<int>& A) {
 4         vector<int> copyA(A), ret;
 5         sort(copyA.begin(), copyA.end());
 6         if (A == copyA) {
 7             return ret;
 8         }
 9         n = A.size();
10         flip(A, ret, n, copyA);
11         // print(A);
12         return ret;
13     }
14     void flip(vector<int>& A, vector<int>& ret, int cur, const vector<int> sortedA) {
15         if (cur == 1) {
16             return;
17         }
18         auto iter = find(A.begin(), A.end(), cur);
19         const int idx = distance(A.begin(), iter);
20         if (idx != 0) {
21             reverse(A.begin(), iter + 1);
22             // print(A);
23             ret.push_back(idx + 1);
24         }
25         if (A == sortedA) {
26             return;
27         }
28         reverse(A.begin(), A.begin() + cur);
29         // print(A);
30         ret.push_back(cur);
31         if (A == sortedA) {
32             return;
33         }
34         flip(A, ret, cur-1, sortedA);
35     }
36     void print(vector<int>& A) {
37         for (auto e : A) {
38             printf("%d ", e);
39         }
40         printf("\n");
41     }
42     int n;
43 };
View Code

 

【971】Flip Binary Tree To Match Preorder Traversal(第三题 6分)

 

【972】Equal Rational Numbers(第四题 8分)(第四题比赛的时候不会做,2019年1月17日算法群里的每日一题)

 给了两个字符串 S 和 T,每个代表一个非负的有理数,如果他们相等的话,返回 True。有如下三种格式:

  • <IntegerPart> (e.g. 0, 12, 123)
  • <IntegerPart><.><NonRepeatingPart>  (e.g. 0.5, 1., 2.12, 2.0001)
  • <IntegerPart><.><NonRepeatingPart><(><RepeatingPart><)> (e.g. 0.1(6), 0.9(9), 0.00(1212))
Example 1:
Input: S = "0.(52)", T = "0.5(25)"
Output: true
Explanation:
Because "0.(52)" represents 0.52525252..., and "0.5(25)" represents 0.52525252525..... , the strings represent the same number.

Example 2:
Input: S = "0.1666(6)", T = "0.166(66)"
Output: true

Example 3:
Input: S = "0.9(9)", T = "1."
Output: true
Explanation: 
"0.9(9)" represents 0.999999999... repeated forever, which equals 1.  [See this link for an explanation.]
"1." represents the number 1, which is formed correctly: (IntegerPart) = "1" and (NonRepeatingPart) = ""

数据规模:

  1. Each part consists only of digits.
  2. The <IntegerPart> will not begin with 2 or more zeros.  (There is no other restriction on the digits of each part.)
  3. 1 <= <IntegerPart>.length <= 4
  4. 0 <= <NonRepeatingPart>.length <= 4
  5. 1 <= <RepeatingPart>.length <= 4

题解:我们可以考虑把整个字符串转换成double,如果没有循环节的话直接调用库函数 stod,如果有循环节的话,扩展一下循环节。因为循环节的长度最长也才4位,它可能有 1,2, 3, 4 这么长,所以我们可以拓展循环节到12位长度,这样不管它是1,2,3,4最后两个数都能拓展成一样的。

技术分享图片
 1 class Solution {
 2 public:
 3     bool isRationalEqual(string S, string T) {
 4         return abs(StrToDouble(S) - StrToDouble(T)) < 1e-10;
 5     }
 6     double StrToDouble(string s) {
 7         auto pos = s.find(();
 8         if (pos == string::npos) {
 9             return stod(s);
10         }
11         string base = s.substr(0, pos), repeat = s.substr(pos + 1, s.size() - 1 - pos - 1);
12         while (base.size() < 20) {
13             base += repeat;
14         }
15         return stod(base);
16     }
17 };
View Code

 

 

Contest 119(2019年1月13日)(题号973-976)

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

总结:3/4,rank:1024/3847 第二题超时了好几次,第三题有个负数没有考虑。第三题也想了挺久的。orz

【973】K Closest Points to Origin(第一题 3分)

给了一堆坐标,返回离原点最近的 K 个坐标。

题解:直接排序,返回前 K 个。

技术分享图片
 1 class Solution {
 2 public:
 3     vector<vector<int>> kClosest(vector<vector<int>>& points, int K) {
 4         const int n = points.size();
 5         if (n <= K) {
 6             return points;
 7         }
 8         vector<pair<int, vector<int>>> dis(n);
 9         for (int i = 0; i < n; ++i) {
10             auto p = points[i];
11             int d = p[0] * p[0] + p[1] * p[1];
12             dis[i] = make_pair(d, p);
13         }
14         sort(dis.begin(), dis.end());
15         vector<vector<int>> ans(K);
16         for (int i = 0; i < K; ++i) {
17             ans[i] = dis[i].second;
18         }
19         return ans;
20     }
21 };
View Code

 

【976】Largest Perimeter Triangle(第二题 4分)

给了一个数组 A 代表边长,求能组成周长最长的三角形的周长。

数据规模: 

  1. 3 <= A.length <= 10000
  2. 1 <= A[i] <= 10^6

题解:先排序,从大到小排序。第一个能组成的三角形就是所求的,而且这三个边长的变量元素一定是相邻的三个元素。想象一下如果相邻的第三个元素不能和前两个元素组成三角形,那么后面的元素肯定小于等于第三个元素,更加不能组成三角形。 

技术分享图片
 1 class Solution {
 2 public:
 3     int largestPerimeter(vector<int>& A) {
 4         const int n = A.size();
 5         sort(A.begin(), A.end(), cmp);
 6         int ans = 0;
 7         for (int i = 0; i < n - 2; ++i) {
 8             int l1 = A[i], l2 = A[i+1], l3 = A[i+2];
 9             if (l2 + l3 <= l1) {continue;}
10             if (l1 - l2 >= l3 || l1 - l3 >= l2 || l2 - l3 >= l1) {continue;}
11             ans = l1 + l2 + l3;
12             if (ans > 0) {
13                 return ans;
14             }
15         }
16         return ans;
17     }
18     static bool cmp(const int& a, const int& b) {
19         return a > b;
20     }
21 };
View Code

  

【974】Subarray Sums Divisible by K(第三题 6分)

 

【975】Odd Even Jump(第四题 8分)

 

Contest 120(2019年1月20日)(题号977-980)

结果:3/4,rank:557 / 3876。做了第一题,第二题,第四题,第三题差点就做出来了,orz。

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

【977】Squares of a Sorted Array(第一题 2分)

给了一个排序数组,里面有正有负,返回这个数组的平方数组,需要排序排好。

Example 1:
Input: [-4,-1,0,3,10]
Output: [0,1,9,16,100]

题解:我是先用了一个 lower_bound 找到了 0  的位置,然后 2 pointers,一个指向正数往大了走,一个指向负数往小了走。

技术分享图片
 1 class Solution {
 2 public:
 3     vector<int> sortedSquares(vector<int>& A) {
 4         const int n = A.size();
 5         auto iter = lower_bound(A.begin(), A.end(), 0);
 6         vector<int> ret(n);
 7         if (iter == A.begin() || iter == A.end()) {
 8             for (int i = 0; i < n; ++i) {
 9                 ret[i] = A[i] * A[i];
10             }
11             if (iter == A.end()) {
12                 reverse(ret.begin(), ret.end());
13             }
14         } else {
15             int p1 = distance(A.begin(), iter), p2 = p1 - 1; //++p1, --p2
16             int cnt = 0;
17             while (p1 < n && p2 >= 0) {
18                 if (abs(A[p2]) < abs(A[p1])) {
19                     ret[cnt++] = A[p2] * A[p2];
20                     --p2;
21                 } else {
22                     ret[cnt++] = A[p1] * A[p1];
23                     ++p1;
24                 }
25             }
26             while (p1 < n) {
27                 ret[cnt++] = A[p1] * A[p1];
28                 ++p1;
29             }
30             while (p2 >= 0) {
31                 ret[cnt++] = A[p2] * A[p2];
32                 --p2;
33             }
34         }
35         return ret;
36     }
37 };
View Code

 

【978】Longest Turbulent Subarray(第二题 5分)

找出最长的连续子数组,子数组中的元素满足如下性质之一,

  • For i <= k < jA[k] > A[k+1] when k is odd, and A[k] < A[k+1] when k is even;
  • OR, for i <= k < jA[k] > A[k+1] when k is even, and A[k] < A[k+1] when k is odd.

返回最长子数组的长度。

题解:我们求原数组的差分数组,diff[i] = A[i]-A[i-1], 然后只保留正负号(正数是1,负数是-1)。我们用dp求最长的连续子数组,dp[i] 代表以 i 为结尾的 diff 数组的最长的连续正负子序列的长度。

if (diff[i] * diff[i-1] == -1) {
    dp[i] = dp[i-1]+1;
} else {
    dp[i] = 1;
} 
技术分享图片
 1 class Solution {
 2 public:
 3     int maxTurbulenceSize(vector<int>& A) {
 4         const int n = A.size();
 5         if (n <= 1) {
 6             return n;
 7         }
 8         vector<int> diff(n, 0);
 9         for (int i = 1; i < n; ++i) {
10             diff[i] = A[i] - A[i-1];
11             if (diff[i] < 0) {
12                 diff[i] = -1;
13             } else if (diff[i] > 0) {
14                 diff[i] = 1;
15             }
16         }
17         // vector<int> dp(n, 1);
18         // dp[0] = 0;
19         int cur = 1, pre = 1;
20         int ret = 1;
21         for (int i = 2; i < n; ++i) {
22             if (diff[i] * diff[i-1] == -1) {
23                 //dp[i] = dp[i-1] + 1;
24                 cur = pre + 1;
25                 ret = max(ret, cur);
26             } else {
27                 cur = 1;
28             }
29             pre = cur;
30         }
31         return ret + 1;
32     }
33 };
View Code

 

【979】Distribute Coins in Binary Tree(第三题 6分)

给了一棵二叉树,上面有 N 个节点,N 个节点上面有 N 个coin,我们把 一个节点上的一个硬币移动到它的儿子节点或者父节点,称为一个 move,问把 N 个节点上每个节点上都有一个 coin,问需要多少步数。

题解:我比赛的时候先序遍历,中序遍历都想了,就是没想后序遍历,后来想到了,结果就差一点点ac了,尴尬。

我们可以这么思考,如果一个节点是叶子节点,它上面有三个硬币,那么它可以自己留一个,上交给爸爸两个,返回2。如果它上面有1个硬币,它就可以自己留着一个,不上交爸爸,返回0。如果它上面没有硬币,它就可以找它爸爸要一个,返回-1。

爸爸接到了儿子的信息,它要修改下自己的数量。儿子上交了,它就加上,儿子找它要,它就先给它儿子。然后我们用每次要的数量的绝对值累加步数。dfs一下,结果就呼之欲出了。

技术分享图片
 1 /**
 2  * Definition for a binary tree node.
 3  * struct TreeNode {
 4  *     int val;
 5  *     TreeNode *left;
 6  *     TreeNode *right;
 7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 8  * };
 9  */
10 class Solution {
11 public:
12     int moves = 0;
13     int distributeCoins(TreeNode* root) {
14         if (!root) { return 0; }
15         dfs(root);
16         return moves;
17     }
18     int dfs(TreeNode* root) {  //return states: 0->no need, -3->need 3 coins, +3->give 3 coins
19         if (!root) {return 0;}
20         if (!root->left && !root->right) {
21             return root->val - 1;
22         }
23         int l = dfs(root->left);
24         root->val += l;
25         moves += abs(l);
26         int r = dfs(root->right);
27         root->val += r;
28         moves += abs(r);
29         return root->val - 1;
30     }
31 };
View Code

 

【980】Unique Paths III(第四题 7分)

 给了一个2D grid,上面 1 代表起点,2代表重点,0代表可以走的路,-1代表障碍。题目要求我们从起点开始,遍历过所有能走的路,走到终点。求一共有多少中走法。

  1. 1 <= grid.length * grid[0].length <= 20

题解:我直接dfs了,数据规模很小。此外本题还可以状压dp,昨天被旅行商问题搞出了心理阴影,所以,今天先不想状压dp了。orz

技术分享图片
 1 class Solution {
 2 public:
 3     int visTot = 0, obs = 0;
 4     int n, m, total;
 5     int ret = 0;
 6     vector<int> begin{-1, -1}, end{-1, -1};
 7     vector<int> dirx = {-1, 0, 1, 0};
 8     vector<int> diry = {0, -1, 0, 1};
 9     int uniquePathsIII(vector<vector<int>>& grid) {
10         n = grid.size(), m = grid[0].size();
11         for (int i = 0; i < n; ++i) {
12             for (int j = 0; j < m; ++j) {
13                 if (grid[i][j] == 1) {
14                     begin = {i, j};
15                 } else if (grid[i][j] == 2) {
16                     end = {i, j};
17                 } else if (grid[i][j] == -1) {
18                     obs++;
19                 }
20             }
21         }
22         total = n * m - obs;
23         vector<vector<int>> visit = grid;
24         dfs(grid, visit, begin[0], begin[1]);
25         return ret;
26     }
27     void dfs(const vector<vector<int>>& grid, vector<vector<int>>& visit, int curx, int cury) {
28         if (curx == end[0] && cury == end[1] && visTot + 1 == total) {
29             ++ret;
30         }
31         visit[curx][cury] = 3;
32         visTot++;
33         for (int i = 0; i < 4; ++i) {
34             int newx = curx + dirx[i], newy = cury + diry[i];
35             if (newx >= 0 && newx < n && newy >= 0 && newy < m && visit[newx][newy] != -1 && visit[newx][newy] != 3) {
36                 dfs(grid, visit, newx, newy);
37             }
38         }
39         visit[curx][cury] = 0;
40         visTot--;
41     }
42 };
View Code

 

 

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

原文:https://www.cnblogs.com/zhangwanying/p/9998412.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!