力扣第163场周赛

题目1:

给你一个 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 次迁移操作后最终得到的 二维网格。

img

示例 1:

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

img

输入: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]]

提示:

1 <= grid.length <= 50
1 <= grid[i].length <= 50
-1000 <= grid[i][j] <= 1000
0 <= k <= 100

链接:https://leetcode-cn.com/problems/shift-2d-grid


题目说按着一定的规律去改变一个矩阵,先看数据,50和100,也就是50 * 50 * 100 复杂度可以用来暴力,那么我们开一个辅助的数组,把操作后的数据存起来,再赋值回去就可以了。

class Solution {
public:
    vector<vector<int>> shiftGrid(vector<vector<int>>& grid, int k) {
       vector<vector<int>> tmp=grid;
       int n=grid.size(),m=grid[0].size();
       for(int z=0;z<k;z++)
       {
           for(int i=0;i<grid.size();i++){
               for(int j=0;j<grid[i].size();j++){
                   if(i==n-1&&j==m-1){
                       tmp[0][0]=grid[i][j];
                   }else if(j==m-1){
                        tmp[i+1][0]=grid[i][j];
                   }else tmp[i][j+1]=grid[i][j];
               }
           }
           grid=tmp;
       }
        return grid;
    }
};

题目2:

给出一个满足下述规则的二叉树:

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 是否存在于还原后的二叉树中并返回结果。

img

输入:

[“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

提示:

TreeNode.val == -1
二叉树的高度不超过 20
节点的总数在 [1, 10^4] 之间
调用 find() 的总次数在 [1, 10^4] 之间
0 <= target <= 10^6

链接:https://leetcode-cn.com/problems/find-elements-in-a-contaminated-binary-tree

题目的意思就是给你一个头节点,然后所有节点的数据都是-1,我们要做的是把每个左节点数据变为父节点的2 * x+1,以及把右节点变为2 * x+2,用bfs就可以实现了,树的层序遍历。同样的,我是建立了一个辅助的数组,开到(1<<20),把每个可以还原的点给标记一下下。之后查询的时候O(1)复杂度的查询。也有另外一种做法就是搜索,先把树给变好,然后直接搜索左右节点,但是这个不是二叉搜索树的结构。所以搜索的复杂度就是O(n)的了。

class FindElements {
public:
    TreeNode *Root;
    int ok[1<<(20+1)];
    FindElements(TreeNode* root) {
        queue<TreeNode*> q;
        memset(ok,0,sizeof ok);
        q.push(root);
        root->val=0;
        ok[0]=1;
        while(!q.empty()){
            TreeNode *z=q.front();q.pop();
            int val=z->val;
            ok[val]=1;
            if(z->left!=NULL){
                z->left->val=val*2+1;
                q.push(z->left);
            }
            if(z->right!=NULL){
                z->right->val=val*2+2;
                q.push(z->right);
            }
        }
    }
    bool find(int target) {
        if(ok[target])return true;
        else return false;
    }
};

题目3:

给你一个整数数组 nums,请你找出并返回能被三整除的元素最大和。

示例 1:

输入:nums = [3,6,5,1,8]
输出:18
解释:选出数字 3, 6, 1 和 8,它们的和是 18(可被 3 整除的最大和)。

提示:

  • 1 <= nums.length <= 4 * 10^4
  • 1 <= nums[i] <= 10^4

链接:https://leetcode-cn.com/problems/greatest-sum-divisible-by-three

这题蛮复杂也有意思,但是我们可以围绕3想一想,数字除以三有余1,2,0三种情况,我们需要计算的是余0的最大值。那么有一个当前的数字a,假如a+余1的最大值的余数为零,如5+7,这种情况7是余1可以达到的最大值,如果我们相加这两个数字的和也就是和余0大于原本余0的情况,那余0最大值就改变了,为12。我们接着去看,如果a+余1的最大值余数为1,如5+8为13,那假如这值大于余1的最大值,我们同样也可以更新余1的最大值,同理,最大值余2的情况我们也可以算的。以上我们是用+余1的最大值来判断的。同时我们也需要用余2余0,来判断0,1,2的情况。用前面的状态决定现在的状态,是不是很熟悉?DP。可以用一个数组a来存以前的余0,1,2最大值,再用数组tmp来计算加上当前数余0,1,2的最大值,之后再把tmp赋值给原来的数组a。

class Solution {
public:
    int maxSumDivThree(vector<int>& nums) {
        int a[3];a[0]=0;a[1]=-1;a[2]=-1;//0余0为0,没有余1,没用余2
        for(int i=0;i<nums.size();i++){
            int tmp[3];
            tmp[0]=tmp[1]=tmp[2]=-1;//要赋值为-1因为还不知道有没有变化
            for(int j=0;j<3;j++){
                if(a[j]==-1)continue;//如果原来的余数数组没用值,就没法计算
                int sum=a[j]+nums[i];
                if(sum>tmp[sum%3]){
                    tmp[sum%3]=sum;
                }
            }
            for(int j=0;j<3;j++){
                a[j]=max(a[j],tmp[j]);
            }
        }
        return a[0];
    }
};

第四题:

「推箱子」是一款风靡全球的益智小游戏,玩家需要将箱子推到仓库中的目标位置。

游戏地图用大小为 n * m 的网格 grid 表示,其中每个元素可以是墙、地板或者是箱子。

现在你将作为玩家参与游戏,按规则将箱子 ‘B’ 移动到目标位置 ‘T’ :

玩家用字符 ‘S’ 表示,只要他在地板上,就可以在网格中向上、下、左、右四个方向移动。
地板用字符 ‘.’ 表示,意味着可以自由行走。
墙用字符 ‘#’ 表示,意味着障碍物,不能通行。
箱子仅有一个,用字符 ‘B’ 表示。相应地,网格上有一个目标位置 ‘T’。
玩家需要站在箱子旁边,然后沿着箱子的方向进行移动,此时箱子会被移动到相邻的地板单元格。记作一次「推动」。
玩家无法越过箱子。
返回将箱子推到目标位置的最小 推动 次数,如果无法做到,请返回 -1。

img

输入:grid = [["#","#","#","#","#","#"],
["#",“T”,"#","#","#","#"],
["#",".",".",“B”,".","#"],
["#",".","#","#",".","#"],
["#",".",".",".",“S”,"#"],
["#","#","#","#","#","#"]]
输出:3
解释:我们只需要返回推箱子的次数。

提示:

1 <= grid.length <= 20
1 <= grid[i].length <= 20
grid 仅包含字符 ‘.’, ‘#’, ‘S’ , ‘T’, 以及 ‘B’。
grid 中 ‘S’, ‘B’ 和 ‘T’ 各只能出现一个。

链接:https://leetcode-cn.com/problems/minimum-moves-to-move-a-box-to-their-target-location

第四题过于复杂就小讲一下下,三维数组是为了存储每个点的不同方向的。箱子能不能移动是需要看人能不能走过去。所以需要判断一下下。放下自己的代码~

class Solution {
public:
    int nxt[4][2]={0,1,1,0,-1,0,0,-1};
    struct node{
        int x,y,cx,cy,cnt;
    };
    vector<vector<char>> tu;
    int vis[30][30];
    int vis1[30][30][5];
    bool ok(int x,int y,int ex,int ey){
        if(x==ex&&y==ey)return true;
        for(int i=0;i<4;i++){
            int a=x+nxt[i][0],b=y+nxt[i][1];
            if(a<0||b<0||a>=m||b>=n)continue;
            if(tu[a][b]!='#'&&vis[a][b]==0){
                vis[a][b]=1;
                if(ok(a,b,ex,ey))return true;
            }
        }
        return false;
    }
    int eex,eey;
    int m,n;
    int bfs(int x,int y,int px,int py){
        queue<node> q;
        q.push({x,y,px,py,0});
        while(!q.empty()){
            node tmp=q.front();q.pop();
            int nx=tmp.x,ny=tmp.y;//箱子
            if(nx==eex&&ny==eey)return tmp.cnt;
            for(int i=0;i<4;i++){
                int dx=nx+nxt[i][0];int dy=ny+nxt[i][1];
                if(dx<0||dy<0||dx>=m||dy>=n||vis1[dx][ny][i]||tu[dx][dy]=='#')continue;
                vis1[nx][ny][i]=1;
                memset(vis,0,sizeof vis);vis[nx][ny]=1;
                if(ok(tmp.cx,tmp.cy,nx-nxt[i][0],ny-nxt[i][1]))
                {
                    q.push({dx,dy,nx-nxt[i][0],ny-nxt[i][1],tmp.cnt+1});
                    
                }
            }
        }
        return -1;
    }
    
    int minPushBox(vector<vector<char>>& grid) {
        tu=grid;
        int bx,by;
        int sx,sy;
        m=grid.size();n=grid[0].size();
        for(int i=0;i<grid.size();i++){
            for(int j=0;j<grid[i].size();j++){
                if(grid[i][j]=='B'){
                    bx=i;by=j;  
                }
                if(grid[i][j]=='T'){
                    eex=i;eey=j;
                }
                if(grid[i][j]=='S'){
                    sx=i;sy=j;
                }
            }
        }
        return bfs(bx,by,sx,sy);
    }
};

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值