LeetCode 2019年第163场周赛

1260. 二维网格迁移

题目描述

给你一个 n 行 m 列的二维网格 grid 和一个整数 k。你需要将 grid 迁移 k 次。 每次「迁移」操作将会引发下述活动: 位于 grid[i][j] 的元素将会移动到 grid[i][j + 1]。 位于 grid[i][m - 1] 的元素将会移动到 grid[i + 1][0]。 位于 grid[n - 1][m - 1] 的元素将会移动到 grid[0][0]。 请你返回 k 次迁移操作后最终得到的 二维网格。 示例 1: 输入:grid = [[1,2,3],[4,5,6],[7,8,9]], k = 1 输出:[[9,1,2],[3,4,5],[6,7,8]] 示例 2: 输入:grid = [[3,8,1,9],[19,7,2,5],[4,6,11,10],[12,0,21,13]], k = 4 输出:[[12,0,21,13],[3,8,1,9],[19,7,2,5],[4,6,11,10]] 示例 3: 输入:grid = [[1,2,3],[4,5,6],[7,8,9]], k = 9 输出:[[1,2,3],[4,5,6],[7,8,9]] 提示: 1 <= grid.length <= 50 1 <= grid[i].length <= 50 -1000 <= grid[i][j] <= 1000 0 <= k <= 100

题解1

之前做过一个一维数组元素平移,最后面的移到前面。比赛时首先想到的是先把二维数组转成一维数组,然后平移元素。注意平移周期为数组长度。可以先对平移长度取模。

代码1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
时间复杂度为o(m * n)
空间复杂度为o(m * n)
*/
class Solution {
public:
vector<vector<int>> shiftGrid(vector<vector<int>>& grid, int k) {
vector<int>tmp;
int rows = grid.size(), cols = grid[0].size();
for(int i = 0; i < grid.size(); ++i){//将二维数组转成一维数组
for(int j = 0; j < grid[i].size(); ++j){
tmp.push_back(grid[i][j]);
}
}
int len = tmp.size();
k = k % len;
for(int i = 0; i < len; ++i){//对元素进行平移,不过这里是逆向思维
grid[i / cols][i % cols] = tmp[(i - k + len) % len];
}
return grid;
}
};

1261. 在受污染的二叉树中查找元素

题目描述

给出一个满足下述规则的二叉树: root.val == 0 如果 treeNode.val == x 且 treeNode.left != null,那么 treeNode.left.val == 2 * x + 1 如果 treeNode.val == x 且 treeNode.right != null,那么 treeNode.right.val == 2 * x + 2 现在这个二叉树受到「污染」,所有的 treeNode.val 都变成了 -1。 请你先还原二叉树,然后实现 FindElements 类: FindElements(TreeNode* root) 用受污染的二叉树初始化对象,你需要先把它还原。 bool find(int target) 判断目标值 target 是否存在于还原后的二叉树中并返回结果。 示例 1: 输入: [“FindElements”,”find”,”find”] [[[-1,null,-1]],[1],[2]] 输出: [null,false,true] 解释: FindElements findElements = new FindElements([-1,null,-1]); findElements.find(1); // return False findElements.find(2); // return True 示例 2: 输入: [“FindElements”,”find”,”find”,”find”] [[[-1,-1,-1,-1,-1]],[1],[3],[5]] 输出: [null,true,true,false] 解释: FindElements findElements = new FindElements([-1,-1,-1,-1,-1]); findElements.find(1); // return True findElements.find(3); // return True findElements.find(5); // return False 示例 3: 输入: [“FindElements”,”find”,”find”,”find”,”find”] [[[-1,null,-1,-1,null,-1]],[2],[3],[4],[5]] 输出: [null,true,false,false,true] 解释: FindElements findElements = new FindElements([-1,null,-1,-1,null,-1]); findElements.find(2); // return True findElements.find(3); // return False findElements.find(4); // return False findElements.find(5); // return True 提示: TreeNode.val == -1 二叉树的高度不超过 20 节点的总数在 [1, 10^4] 之间 调用 find() 的总次数在 [1, 10^4] 之间 0 <= target <= 10^6

题解1

题目大意是已经给出二叉树的结构,但是结点值不正确,首先根据给定的规则,对二叉树节点重新赋值。然后写出find函数。 对于二叉树的构建及find函数常见的方法是递归的方式,但是后来我发现find的传入参数不是没有root。实现有点麻烦,后来用的是队列实现的。类似于BFS

代码1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class FindElements {
public:
TreeNode *res;
FindElements(TreeNode* root) {
res = root;
if(res == NULL){
return;
}
queue<TreeNode*>que;
TreeNode* frt;
res->val = 0;
que.push(res);
while(!que.empty()){//BFS为节点赋值
frt = que.front();
que.pop();
if(frt->left != NULL){
frt->left->val = frt->val * 2 + 1;
que.push(frt->left);
}
if(frt->right != NULL){
frt->right->val = frt->val * 2 + 2;
que.push(frt->right);
}
}
}
bool find(int target) {
if(res == NULL){
return false;
}
else{
queue<TreeNode*>que;
TreeNode* frt;
que.push(res);
while(!que.empty()){//BFS遍历节点,来寻找节点
frt = que.front();
que.pop();
if(frt->val == target){
return true;
}
if(frt->left != NULL){
que.push(frt->left);
}
if(frt->right != NULL){
que.push(frt->right);
}
}
return false;
}
}
};

/**
* Your FindElements object will be instantiated and called as such:
* FindElements* obj = new FindElements(root);
* bool param_1 = obj->find(target);
*/

1262. 可被三整除的最大和

题目描述

给你一个整数数组 nums,请你找出并返回能被三整除的元素最大和。 示例 1: 输入:nums = [3,6,5,1,8] 输出:18 解释:选出数字 3, 6, 1 和 8,它们的和是 18(可被 3 整除的最大和)。 示例 2: 输入:nums = [4] 输出:0 解释:4 不能被 3 整除,所以无法选出数字,返回 0。 示例 3: 输入:nums = [1,2,3,4,4] 输出:12 解释:选出数字 1, 3, 4 以及 4,它们的和是 12(可被 3 整除的最大和)。 提示: 1 <= nums.length <= 4 * 10^4 1 <= nums[i] <= 10^4

题解1

这个题比赛的时候,思路没理清,导致写出来的代码bug多,赛后想了感觉很简单。 1. 所有元素排序 2. 求所有元素之和对3的余数res,期间各存下余数为1和余数为2的最小的2个数(4个数) 3. res = 0的话,被三整除的最大和为元素和。res=1的话需要去除1个余数为1的数或2个余数为2的数,需要比较一个,选择和大的一个。res=2的话需要去除2个余数为1的数或1个余数为2的数,同样比较取和较大的一种方案

代码1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Solution {
public:
int maxSumDivThree(vector<int>& nums) {
sort(nums.begin(), nums.end());

int sum = 0 , mod = 0, len = nums.size(), res;
vector<int>v1, v2;
for(int i = 0; i < len; ++i){
sum = sum + nums[i];
mod = (mod + nums[i]) % 3;
if(v1.size() < 2 && nums[i] % 3 == 1){//存储至多2个最小的余数为1的
v1.push_back(nums[i]);
}
else if(v2.size() < 2 && nums[i] % 3 == 2){//存储至多2个最小的余数为2的
v2.push_back(nums[i]);
}
}
if(mod == 0){//刚好余数为0
res = sum;
}
else if(mod == 1){//需去除1个余数为1的或2个余数为2的
int num1 = sum - (v1.size() > 0?v1[0]:sum);
int num2 = sum - (v2.size() > 1?v2[0] + v2[1]:sum);
res = max(num1, num2);
}
else{//需去除2个余数为1的或者1个余数为2的
int num1 = sum - (v1.size() > 1?v1[0] + v1[1]:sum);
int num2 = sum - (v2.size() > 0?v2[0]:sum);
res = max(num1, num2);
}
return res;
}
};

1263. 推箱子

题目描述

「推箱子」是一款风靡全球的益智小游戏,玩家需要将箱子推到仓库中的目标位置。 游戏地图用大小为 n * m 的网格 grid 表示,其中每个元素可以是墙、地板或者是箱子。 现在你将作为玩家参与游戏,按规则将箱子 ‘B’ 移动到目标位置 ‘T’ : 玩家用字符 ‘S’ 表示,只要他在地板上,就可以在网格中向上、下、左、右四个方向移动。 地板用字符 ‘.’ 表示,意味着可以自由行走。 墙用字符 ‘#’ 表示,意味着障碍物,不能通行。 箱子仅有一个,用字符 ‘B’ 表示。相应地,网格上有一个目标位置 ‘T’。 玩家需要站在箱子旁边,然后沿着箱子的方向进行移动,此时箱子会被移动到相邻的地板单元格。记作一次「推动」。 玩家无法越过箱子。 返回将箱子推到目标位置的最小 推动 次数,如果无法做到,请返回 -1。 示例 1: 输入:grid = [[“#”,”#”,”#”,”#”,”#”,”#”], [“#”,”T”,”#”,”#”,”#”,”#”], [“#”,”.”,”.”,”B”,”.”,”#”], [“#”,”.”,”#”,”#”,”.”,”#”], [“#”,”.”,”.”,”.”,”S”,”#”], [“#”,”#”,”#”,”#”,”#”,”#”]] 输出:3 解释:我们只需要返回推箱子的次数。 示例 2: 输入:grid = [[“#”,”#”,”#”,”#”,”#”,”#”], [“#”,”T”,”#”,”#”,”#”,”#”], [“#”,”.”,”.”,”B”,”.”,”#”], [“#”,”#”,”#”,”#”,”.”,”#”], [“#”,”.”,”.”,”.”,”S”,”#”], [“#”,”#”,”#”,”#”,”#”,”#”]] 输出:-1 示例 3: 输入:grid = [[“#”,”#”,”#”,”#”,”#”,”#”], [“#”,”T”,”.”,”.”,”#”,”#”], [“#”,”.”,”#”,”B”,”.”,”#”], [“#”,”.”,”.”,”.”,”.”,”#”], [“#”,”.”,”.”,”.”,”S”,”#”], [“#”,”#”,”#”,”#”,”#”,”#”]] 输出:5 解释:向下、向左、向左、向上再向上。 示例 4: 输入:grid = [[“#”,”#”,”#”,”#”,”#”,”#”,”#”], [“#”,”S”,”#”,”.”,”B”,”T”,”#”], [“#”,”#”,”#”,”#”,”#”,”#”,”#”]] 输出:-1 提示: 1 <= grid.length <= 20 1 <= grid[i].length <= 20 grid 仅包含字符 ‘.’, ‘#’, ‘S’ , ‘T’, 以及 ‘B’。 grid 中 ‘S’, ‘B’ 和 ‘T’ 各只能出现一个。

题解1

参照题解 如果只有箱子没有人,只是将箱子移到目标位置,就是常见的BFS问题。而这个题有两个对象,箱子和人,要保证箱子能被推到目标位置。加入队列的信息除了箱子的坐标还有人的坐标,随着人的移动来判断人是否能走到箱子的位置,能表示箱子移动,步数加1;否则只是人的位置发生移动,此时步数并未增加。此外,标记对象也发生改变,以前只是箱子这个二元组,现在变成了人和箱子这个四元组。因为人移动带来的步数并不一定增长,这里需要用到优先队列,每次选取步数最小的来移动。

代码1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
struct cmp{
bool operator()(vector<int>v1, vector<int>v2){//定义优先级别
return v1[0] > v2[0];
}
};
int dir[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};//定义移动方向
class Solution {
public:
int minPushBox(vector<vector<char>>& grid) {
set<vector<int> >mark;//用set来标记
int rows = grid.size(), cols = grid[0].size();
int x1, x2, y1, y2, x3, y3, next_x, next_y, dist;
vector<int>v;
priority_queue<vector<int>, vector<vector<int>>, cmp>que;//定义优先队列
for(int i = 0; i < rows; ++i){
for(int j = 0; j < cols; ++j){
if(grid[i][j] == 'S'){//玩家
x1 = i;
y1 = j;
}
else if(grid[i][j] == 'B'){//箱子
x2 = i;
y2 = j;
}
else if(grid[i][j] == 'T'){//目标
x3 = i;
y3 = j;
}
}
}
que.push({0, x1, y1, x2, y2});//初始化
mark.insert({x1, y1, x2, y2});
while(!que.empty()){
v = que.top();
que.pop();
if(v[3] == x3 && v[4] == y3){
return v[0];
}
for(int i = 0; i < 4; ++i){
x1 = v[1] + dir[i][0];
y1 = v[2] + dir[i][1];
dist = v[0];
if(x1 < 0 x1 >= rows y1 < 0 y1 >= cols){
continue;
}
if(grid[x1][y1] != '#'){
if(x1 == v[3] && y1 == v[4]){
x2 = v[3] + dir[i][0];
y2 = v[4] + dir[i][1];
if(x2 >= 0 && x2 < rows && y2 >= 0 && y2 < cols && grid[x2][y2] != '#'){
if(mark.find({x1, y1, x2, y2}) == mark.end()){//未访问过
mark.insert({x1, y1, x2, y2});
que.push({dist + 1, x1, y1, x2, y2});
}
}
}
else{
if(mark.find({x1, y1, v[3], v[4]}) == mark.end()){//未访问过
mark.insert({x1, y1, v[3], v[4]});
que.push({dist, x1, y1, v[3], v[4]});
}
}
}
}
}
return -1;
}
};