LeetCode之Weekly Contest 92

Posted youdias

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode之Weekly Contest 92相关的知识,希望对你有一定的参考价值。

第一题:转置矩阵

问题:

给定一个矩阵 A, 返回 A 的转置矩阵。

矩阵的转置是指将矩阵的主对角线翻转,交换矩阵的行索引与列索引。

 

示例 1:

输入:[[1,2,3],[4,5,6],[7,8,9]]
输出:[[1,4,7],[2,5,8],[3,6,9]]

示例 2:

输入:[[1,2,3],[4,5,6]]
输出:[[1,4],[2,5],[3,6]]

 

提示:

  1. 1 <= A.length <= 1000
  2. 1 <= A[0].length <= 1000

链接:https://leetcode-cn.com/contest/weekly-contest-92/problems/transpose-matrix/

分析:

行列互换即可

AC Code:

 1 class Solution {
 2 public:
 3     vector<vector<int>> transpose(vector<vector<int>>& A) {
 4         vector<vector<int>> ret;
 5         vector<int> tmp;
 6         if (A.size() == 0)
 7         {
 8             return A;
 9         }
10         int m = A.size();//
11         int n = A[0].size();//
12         for (int j = 0; j < n; j++)
13         {
14             tmp.clear();
15             for (int i = 0; i < m; i++)
16             {
17                 tmp.emplace_back(A[i][j]);
18             }
19             ret.emplace_back(tmp);
20         }
21         return ret;
22     }
23 };

 

其他:

用时最短code(16/28):

 1 class Solution {
 2 public:
 3     vector<vector<int>> transpose(vector<vector<int>>& A) {
 4         int rows = A.size();
 5         int lines = A[0].size();
 6         
 7         vector<vector<int>> ans;
 8         
 9         for(int i = 0; i < lines; i++)
10         {
11             vector<int> temp;
12             ans.push_back(temp);
13         }
14         for(int i = 0; i < rows; i++)
15         {
16             for(int j = 0; j < lines; j++)
17             {
18                 ans[j].push_back(A[i][j]);
19             }
20         }
21         return ans;
22     }
23 };

 

第二题:具有所有最深结点的最小子树

问题:

给定一个根为 root 的二叉树,每个结点的深度是它到根的最短距离。

如果一个结点在整个树的任意结点之间具有最大的深度,则该结点是最深的

一个结点的子树是该结点加上它的所有后代的集合。

返回能满足“以该结点为根的子树中包含所有最深的结点”这一条件的具有最大深度的结点。

 

示例:

输入:[3,5,1,6,2,0,8,null,null,7,4]
输出:[2,7,4]
解释:

技术分享图片

我们返回值为 2 的结点,在图中用黄色标记。
在图中用蓝色标记的是树的最深的结点。
输入 "[3, 5, 1, 6, 2, 0, 8, null, null, 7, 4]" 是对给定的树的序列化表述。
输出 "[2, 7, 4]" 是对根结点的值为 2 的子树的序列化表述。
输入和输出都具有 TreeNode 类型。

 

提示:

  • 树中结点的数量介于 1 和 500 之间。
  • 每个结点的值都是独一无二的。

链接:https://leetcode-cn.com/contest/weekly-contest-92/problems/smallest-subtree-with-all-the-deepest-nodes/

分析:

周赛91中有一个类似的问题,按照同样做法对每个节点进行编码,根节点是0b1,下一次分别是0b10,0b11,然后将得到的数据最后一个即为最底层叶子,根据“宽度”能得到最底层所有叶子,找到公共祖先即为所求节点。

AC Code:

 

 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 //包含该节点的所有子树,最大公共部分就是
13         //包含该节点的所有子树,最大公共部分就是
14     TreeNode* subtreeWithAllDeepest(TreeNode* root) {
15         map<uint64_t, TreeNode*> data;
16         TreeNode* ret = NULL;
17         TreeNode tmp(0);
18         data = DealTreeNode(root, 1);
19         map<uint64_t, TreeNode*>::iterator it;
20         it = data.end();
21         it--;
22         int targetvalue = (*it).first;
23         int length = GetBLength(targetvalue);
24         //uint64_t target = 0xFFFFFFFF;
25         
26         set<uint64_t> sets;
27         for (map<uint64_t, TreeNode*>::reverse_iterator rit = data.rbegin(); rit != data.rend(); rit++)
28         {
29             if (GetBLength((*rit).first) == length)
30             {
31                 sets.insert((*rit).first);
32                 //target = !(target ^ (*rit).first);
33             }
34             else
35             {
36                 break;
37             }
38             
39         }
40         //到这里1知道了层次,2得到了最底层一排数据,但是1000如何确认是10的后代还是1的后代呢?
41         //向上找共同唯一祖先
42         
43         
44         while (sets.size()>1)
45         {
46             sets = GetUper(sets);
47         }
48         int finalcode = *(sets.begin());
49         it = data.find(finalcode);
50         ret = (*it).second;
51         return ret;
52     }
53     set<uint64_t> GetUper(set<uint64_t> setdata)
54     {
55         std::set<uint64_t> ret;
56         for (set<uint64_t>::iterator it = setdata.begin(); it != setdata.end(); it++)
57         {
58             ret.insert((*it) / 2);
59         }
60         return ret;
61     }
62     int GetBLength(int data)
63     {
64         int ret = 0;
65         while (data)
66         {
67             ret++;
68             data /= 2;
69         }
70         return ret;
71     }
72     map<uint64_t, TreeNode*> DealTreeNode(TreeNode* root, int level)
73     {
74         map<uint64_t, TreeNode*> ret;
75         map<uint64_t, TreeNode*> left, right;
76         //TreeNode tmp(0);
77         TreeNode* tmp = NULL;
78         if (root == nullptr)
79         {
80             return ret;
81         }
82         tmp = root;
83         ret.insert(make_pair(level, tmp));
84         left = DealTreeNode(root->left, level * 2);
85         right = DealTreeNode(root->right, level * 2 + 1);
86         for (map<uint64_t, TreeNode*>::iterator it = left.begin(); it != left.end(); it++)
87         {
88             ret.insert(*it);
89         }
90         for (map<uint64_t, TreeNode*>::iterator it = right.begin(); it != right.end(); it++)
91         {
92             ret.insert(*it);
93         }
94         return ret;
95     }
96 
97 };

 

其他:

用时最短code(4/8):

 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 int doit(TreeNode* root)
11 {
12   int tmp1,tmp2;
13   if (root==NULL) return 0;
14   tmp1=doit(root->left);
15   tmp2=doit(root->right);
16   if (tmp1>tmp2) return tmp1+1;
17   else return tmp2+1;
18 }
19 
20 TreeNode* doit2(TreeNode* root,int dep)
21 {
22   if (root==NULL) return NULL;
23   if (dep==1) return root;
24   TreeNode* tmp1=doit2(root->left,dep-1);
25   TreeNode* tmp2=doit2(root->right,dep-1);
26   if (tmp1==NULL) return tmp2;
27   else if (tmp2==NULL) return tmp1;
28   else return root;
29 }
30  
31 class Solution {
32 public:
33     TreeNode* subtreeWithAllDeepest(TreeNode* root) {
34       int tmp=doit(root);
35       return doit2(root,tmp);
36     }
37 };

1.doit 得到层数

2.left  right中如果都含有最低一层,返回root,否则返回含有最低一层的一个

 

第三题:回文素数

问题:

求出大于或等于 N 的最小回文素数。

回顾一下,如果一个数大于 1,且其因数只有 1 和它自身,那么这个数是素数

例如,2,3,5,7,11 以及 13 是素数。

回顾一下,如果一个数从左往右读与从右往左读是一样的,那么这个数是回文数。

例如,12321 是回文数。

 

示例 1:

输入:6
输出:7

示例 2:

输入:8
输出:11

示例 3:

输入:13
输出:101

 

提示:

  • 1 <= N <= 10^8
  • 答案肯定存在,且小于 2 * 10^8

 

链接: https://leetcode-cn.com/contest/weekly-contest-92/problems/prime-palindrome/

分析:

1.回文数比素数更稀疏

2.根据回文数特定,只需要知道一半就能构造出数据。

AC Code:

 

  1 class Solution {
  2 public:
  3 int primePalindrome(int N) {
  4         if (N <= 2)
  5         {
  6             return 2;
  7         }
  8         if (N == 3)
  9         {
 10             return 3;
 11         }
 12         if (N <= 5)
 13         {
 14             return 5;
 15         }
 16         if (N <= 7)
 17         {
 18             return 7;        
 19         }
 20         if (N <= 11)
 21         {
 22             return 11;
 23         }
 24         if (N <= 101)
 25         {
 26             return 101;
 27         }
 28     
 29         //先得到下一个回文数
 30         int ret = N - 1;
 31         while (true)
 32         {
 33             ret = GetNextPalindrome(ret);
 34             //判断是否是素数,如果是,则返回,否则找到下一个回文数继续判断
 35             if (isPrime(ret) == 1)
 36             {
 37                 return ret;
 38             }
 39         }
 40 
 41     }
 42 
 43     int GetNextPalindrome(int data)
 44     {
 45         //100以内的数字已经特殊考虑过,不存在差值1的两个回文数
 46         //首先得到长度,如果是奇数,取前一半+中间值构造,如果是偶数,取前一半构造
 47         int tmpdata=data;
 48         int length = 0;
 49         while (tmpdata)
 50         {
 51             tmpdata /= 10;
 52             length++;
 53         }
 54         //到这里得到数据长度,根据奇偶判断
 55         if (length % 2 == 0)
 56         {
 57             //偶数长度
 58             int highhalf = data / (pow(10, length / 2)); //得到前一半
 59             int lowhalf = data % (int)(pow(10, length / 2)); //低一半
 60             int tmphigh = GetPallindrom(highhalf);
 61             if (tmphigh > lowhalf)
 62             {
 63                 //只需要将高一般构建结果即可
 64                 return data + (tmphigh - lowhalf);
 65             }
 66             else
 67             {
 68                 highhalf += 1;
 69                 int tmplength = 0;
 70                 tmpdata = highhalf;
 71                 while (tmpdata)
 72                 {
 73                     tmpdata /= 10;
 74                     tmplength++;
 75                 }
 76                 if (tmplength == length / 2)
 77                 {
 78                     //没产生进位
 79                     return highhalf*pow(10, tmplength) + GetPallindrom(highhalf);
 80                 }
 81                 else
 82                 {
 83                     //返回奇数个的10X01
 84                     return highhalf*pow(10, tmplength-1) + GetPallindrom(highhalf);
 85                 }
 86                 
 87             }
 88         }
 89         else
 90         {
 91             //奇数长度中间+1即可,如果原来是9,变为10XX01
 92             int highhalf = data / (int)(pow(10, length / 2));
 93             int mid = highhalf % 10;
 94             highhalf /= 10;
 95             int lowhalf = data % (int)(pow(10, length / 2));
 96             int tmphighhalf = GetPallindrom(highhalf);
 97 
 98             //不需要动到中间位置数组
 99             if (tmphighhalf > lowhalf)
100             {
101                 return data + (tmphighhalf - lowhalf);
102             }
103 
104             //需要更新中间数字
105             if (mid < 9)
106             {
107                 return (highhalf * 10 + mid + 1)*pow(10, length / 2) + tmphighhalf;
108             }
109             else
110             {                
111                 //高一半+1不进位,只需要高一半+1,该位变0即可,比如191 -> 202
112                 //如果高位+1后需要进位,如99X,则需要变为1001,即最小的高一位
113                 mid = 0;
114                 highhalf += 1;
115                 tmphighhalf = GetPallindrom(highhalf);
116                 int tmplength = 0;
117                 tmpdata = highhalf;
118                 while (tmpdata)
119                 {
120                     tmpdata /= 10;
121                     tmplength++;
122                 }
123                 if (tmplength == length / 2)
124                 {
125                     //没产生进位
126                     return (highhalf * 10 + mid)*pow(10, length / 2) + tmphighhalf;
127                 }
128                 else
129                 {
130                     //产生了进位 比如999应该变为1001
131                     return highhalf*pow(10, tmplength) + tmphighhalf;
132                 }
133             }
134 
135         }
136     }
137     int isPrime(int data)
138     {
139         if (data == 2 || data == 3)
140         {
141             return 1;
142         }
143         for (int i = 2; i*i <= data; i++)
144         {
145             if (data%i == 0)
146             {
147                 return 0;
148             }
149         }
150         return 1;
151     }
152     int GetPallindrom(int data)
153     {
154         int ret = 0;
155         while (data>0)
156         {
157             ret = ret * 10 + data % 10;
158             data = data / 10;
159         }
160         //cout << "debug:" << data << " -> " << ret << endl;;
161         return ret;
162     }
163 
164 };

 

其他:

用时最短code(0/12)

 1 class Solution {
 2 public:
 3     int primePalindrome(int N) {
 4         if (N<=2) return 2;
 5         string s = to_string(N);
 6         int base = stoi(s.substr(0, (s.size()+1)/2));
 7         int flag = (s.size()%2==0?2:1);
 8         while (true) {
 9             int n = base;
10             for (int k = (flag==1?n/10:n); k>0; k/=10)    n = n*10+k%10;
11             if (n>=N && isPrime(n))
12                 return n;
13             base ++;
14             if ((base==10 || base==100 || base==1000 || base==10000)) {
15                 if (flag==1) base /= 10;
16                 flag = (flag==1?2:1);
17             }
18         }
19         return 0;
20     }
21 
22     bool isPrime(int n) {
23         if (n==2) return true;
24         if (n%2==0) return false;
25         for (int i=3; i*i<=n; i+=2) {
26             if (n%i==0)
27                 return false;
28         }
29         return true;
30     }
31 };

 

 

第四题:获取所有钥匙的最短路径

问题:

  • 用户通过次数0
  • 用户尝试次数4
  • 通过次数0
  • 提交次数6
  • 题目难度Hard

 

给定一个二维网格 grid。 "." 代表一个空房间, "#" 代表一堵墙, "@" 是起点,("a""b", ...)代表钥匙,("A""B", ...)代表锁。

我们从起点开始出发,一次移动是指向四个基本方向之一行走一个单位空间。我们不能在网格外面行走,也无法穿过一堵墙。如果途经一个钥匙,我们就把它捡起来。除非我们手里有对应的钥匙,否则无法通过锁。

假设 K 为钥匙/锁的个数,且满足 1 <= K <= 6,字母表中的前 K 个字母在网格中都有自己对应的一个小写和一个大写字母。换言之,每个锁有唯一对应的钥匙,每个钥匙也有唯一对应的锁。另外,代表钥匙和锁的字母互为大小写并按字母顺序排列。

返回获取所有钥匙所需要的移动的最少次数。如果无法获取所有钥匙,返回 -1 。

 

示例 1:

输入:["@.a.#","###.#","b.A.B"]
输出:8

示例 2:

输入:["@..aA","..B#.","....b"]
输出:6

 

提示:

  1. 1 <= grid.length <= 30
  2. 1 <= grid[0].length <= 30
  3. grid[i][j] 只含有 ‘.‘‘#‘‘@‘‘a‘-‘f 以及 ‘A‘-‘F‘
  4. 钥匙的数目范围是 [1, 6],每个钥匙都对应一个不同的字母,正好打开一个对应的锁。

链接:https://leetcode-cn.com/contest/weekly-contest-92/problems/shortest-path-to-get-all-keys/

分析:

最开始做法是记录每一条路径,从起点开始,得到接下来可能的下一步,如果是#不可达,如果是门但是没有对应钥匙,不可达,如果已经存储在路径中不可达,如果是.或者钥匙,或者是门但有对应钥匙,视为道路,

并存储到路径中。如果拿到了一把新钥匙,清空已经记录的路径,因为原来不可达的位置也许现在能够到达了,运行走回头路。可惜超时了。折腾一周都没搞出来,参考https://blog.csdn.net/yanglingwell/article/details/80984968。

感觉比较巧妙的地方有:

1,同一起点的接下来不同走法采用同一个地图,同时走过的路都设为#,不需要记录就可以避免回头。

2,BFS中当前位置存储在一个队列中,通过{-1,-1}来隔离下一步能够到达的位置。

 

AC Code:

  1 pair<int, int> BFS(const vector<string>& grid, int x, int y, string keysearched, char key, int& len)
  2     {
  3         if (x<0 || x>=grid.size() || y<0 || y>=grid[0].size())
  4         {
  5             return{-1,-1};
  6         }
  7         vector<string> localgrid(grid);
  8         localgrid[x][y] = #;
  9         queue<pair<int, int>> que;
 10         que.push({ x, y });
 11         que.push({ -1, -1 });
 12         int directions[][2] = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };
 13         while (!que.empty())
 14         {
 15             int curx = que.front().first;
 16             int cury = que.front().second;
 17 
 18             que.pop();
 19             if (curx == -1 && que.empty())
 20             {
 21                 continue;
 22             }
 23             else if (cury == -1 && !que.empty())
 24             {
 25                 que.push({ -1, -1 });
 26                 ++len;
 27                 continue;
 28             }
 29 
 30             for (int i = 0; i < 4; i++)
 31             {
 32                 int tx = curx + directions[i][0];
 33                 int ty = cury + directions[i][1];
 34                 if (tx < 0 || tx >= grid.size() || ty < 0 || ty >= grid[0].size())
 35                 {
 36                     continue;
 37                 }
 38                 if (localgrid[tx][ty] == #)
 39                 {
 40                     continue;
 41                 }
 42                 if (isupper(localgrid[tx][ty]) && keysearched.find(tolower(localgrid[tx][ty])) == keysearched.npos)
 43                 {
 44                     continue;
 45                 }
 46 
 47                 //找到了目标key
 48                 if (localgrid[tx][ty]==key && keysearched.find(tolower(localgrid[tx][ty])) == keysearched.npos)
 49                 {
 50                     return{ tx, ty };
 51                 }
 52 
 53                 localgrid[tx][ty] = #;
 54                 que.push({ tx, ty });
 55             }
 56         }
 57         return{ -1, -1 };
 58     }
 59     //返回
 60     int DFS(const vector<string>& grid, int x, int y, string keysearched, string keysearching)
 61     {
 62         //起点越界
 63         if (x<0 || x>=grid.size() || y<0 || y>=grid[0].size())
 64         {
 65             return -1;
 66         }
 67         if (keysearching.empty())
 68         {
 69             return 0;
 70         }
 71 
 72         int ans = -1;
 73         //逐个找key
 74         for (int i = 0; i < keysearching.size(); i++)
 75         {
 76             int nextLen = 1;
 77             pair<int,int> nextpos = BFS(grid, x, y, keysearched, keysearching[i],nextLen);
 78             if (nextpos.first == -1)
 79             {
 80                 continue;
 81             }
 82             string tmpkeysearched(keysearched);
 83             string tmpkeysearching(keysearching);
 84             tmpkeysearched.push_back(grid[nextpos.first][nextpos.second]);
 85             tmpkeysearching.erase(keysearching.find(grid[nextpos.first][nextpos.second]), 1); //find不是在新的string里面?
 86             //tmpkeysearching.erase(tmpkeysearching.find(grid[nextpos.first][nextpos.second]), 1); //find不是在新的string里面?
 87 
 88             int ret = DFS(grid, nextpos.first, nextpos.second, tmpkeysearched, tmpkeysearching);
 89             if (ret == -1)
 90             {
 91                 continue;
 92             }
 93             if (ans == -1 || ans > ret + nextLen)
 94             {
 95                 ans = ret + nextLen;
 96             }
 97 
 98         }
 99         return ans;
100     }
101     //找到起始点坐标,各个钥匙坐标
102     //通过 二维数组jil
103     //https://blog.csdn.net/yanglingwell/article/details/80984968
104     int shortestPathAllKeys(vector<string>& grid) {
105         //参考网络编写code
106         //首先得到起点位置
107         int location_x, location_y=-1;
108         string keys;
109         for (int i = 0; i < grid.size(); i++)
110         {
111             for (int j = 0; j < grid[i].size(); j++)
112             {
113                 if (grid[i][j] == @)
114                 {
115                     location_x = i;
116                     location_y = j;                
117                 }
118                 if (islower(grid[i][j]))
119                 {
120                     keys.push_back(grid[i][j]);
121                 }
122             }
123             
124         }
125 
126         return DFS(grid, location_x, location_y, "", keys);
127 
128 
129     }

 

其他:

用时最短code(8/272)

 1 int t[32][32][1 << 6];
 2 int dr[] = {-1, 0, 1, 0}, dc[] = {0, 1, 0, -1};
 3 class Solution {
 4     
 5 public:
 6     vector<string> g;
 7     int m, n;
 8     int shortestPathAllKeys(vector<string>& grid) {
 9         g = grid;
10         m = grid.size();
11         if(m == 0) return -1;
12         n = grid[0].size();
13         if (n == 0) return -1;
14         for(int i = 0; i < m; i++){
15             for(int j = 0; j < n; j++){
16                 if(grid[i][j] == @) return go(i, j);
17             }
18         }
19         return -1;
20     }
21     int go(int r, int c){
22         int all = 0;
23         for(int i = 0; i < m; i++){
24             for(int j = 0; j < n; j++){
25                 if(a <= g[i][j] && g[i][j] <= z)
26                     all |= (1 <<(g[i][j] - a));
27             }
28         }
29         memset(t, 0xff, sizeof(t));
30         t[r][c][0] = 0;
31         deque<int> que;
32         que.push_back((r << 12) + (c << 6) + 0);
33         while(!que.empty()){
34             int key = que.front();
35             que.pop_front();
36             r = key >> 12;
37             c = (key >> 6) & 0x3f;
38             int k = key & 0x3f;
39             for(int i = 0; i < 4; i++){
40                 int r1 = r + dr[i];
41                 int c1 = c + dc[i];
42                 if(r1 < 0 || c1 < 0 || r1 >= m || c1 >=n) continue;
43                 char ch = g[r1][c1];
44                 if(ch == #) continue;
45                 if(A <= ch && ch <=Z){
46                     int x = 1 << (ch - A);
47                     if( !(x&k)) continue;
48                 }
49                 int k1 = k;
50                 if(a <=ch && ch <=z){
51                     k1 |= (1 <<(ch - a));
52                 }
53                 if (t[r1][c1][k1] < 0){
54                     t[r1][c1][k1] = t[r][c][k] + 1;
55                     if(k1 == all) return t[r1][c1][k1];
56                     que.push_back((r1 << 12) + (c1 << 6) + k1);
57                 }
58             }
59         }
60         return -1;
61         
62     }
63 };

 

以上是关于LeetCode之Weekly Contest 92的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode之Weekly Contest 93

Leetcode Weekly Contest 86

LeetCode(Weekly Contest 188)题解

LeetCode(Weekly Contest 188)题解

LeetCode(Weekly Contest 183)题解

LeetCode(Weekly Contest 187)题解