leetcode周赛125

https://leetcode-cn.com/contest/weekly-contest-125

997. 找到小镇的法官

在一个小镇里,按从 1 到 N 标记了 N 个人。传言称,这些人中有一个是小镇上的秘密法官。

如果小镇的法官真的存在,那么:

  1. 小镇的法官不相信任何人。
  2. 每个人(除了小镇法官外)都信任小镇的法官。
  3. 只有一个人同时满足属性 1 和属性 2 。

给定数组 trust,该数组由信任对 trust[i] = [a, b] 组成,表示标记为 a 的人信任标记为 b 的人。

如果小镇存在秘密法官并且可以确定他的身份,请返回该法官的标记。否则,返回 -1

示例 1:

输入:N = 2, trust = [[1,2]]
输出:2

示例 2:

输入:N = 3, trust = [[1,3],[2,3]]
输出:3

示例 3:

输入:N = 3, trust = [[1,3],[2,3],[3,1]]
输出:-1

示例 4:

输入:N = 3, trust = [[1,2],[2,3]]
输出:-1

示例 5:

输入:N = 4, trust = [[1,3],[1,4],[2,3],[2,4],[4,3]]
输出:3

 

提示:

  1. 1 <= N <= 1000
  2. trust.length <= 10000
  3. trust[i] 是完全不同的
  4. trust[i][0] != trust[i][1]
  5. 1 <= trust[i][0], trust[i][1] <= N

我的作答:

class Solution {
    public int findJudge(int N, int[][] trust) {
        int[][] tr = new int[N][N]; // 用来存储信任关系的二维数组,tr[i][j]==1时表示第i个人被第j个人信任
        for(int i = 0; i < trust.length; i++) {
            tr[trust[i][1]-1][trust[i][0]-1] = 1;
        }
        int find = 0; // 找到符合秘密法官条件的人数
        int last = 0; // 最后一个符合条件的法官的编号
        boolean tmp = false; // 标记位,记录是否需要继续查找,若不符合法官条件则跳出循环
        for(int i = 0; i < N; i++) {
            if(find > 1) {
                return -1;
            }
            
            tmp = false;            
            for(int j = 0; j < N; j++) {
                if(i != j && tr[i][j] == 0) {
                    // 第i个人不被第j个人信任,第i个人不可能成为法官
                    tmp = true;
                    break;
                }
            }
            
            if(!tmp) {
                // 法官不信任任何人
                for(int j = 0; j < N; j++) {
                    if(i != j && tr[j][i] == 1) {
                        tmp = true;
                        break;
                    }
                }
            }
            
            if(!tmp) {
                find++;
                last = i;
            }
        }
        
        if(find == 1) {
            // 找到了符合条件的法官
            return last+1;
        } else {
            return -1;
        }
    }
}

 

uwi的作答:

    class Solution {
        public int findJudge(int N, int[][] trust) {
            int[] ins = new int[N];
            int[] outs = new int[N];
            for(int[] t : trust){
                ins[t[1]-1]++;
                outs[t[0]-1]++;
            }
            int ct = 0;
            int who = -1;
            for(int i = 0;i < N;i++){
                if(ins[i] == N-1 && outs[i] == 0){
                    ct++;
                    who = i;
                }
            }
            if(ct == 1){
                return who+1;
            }else{
                return -1;
            }
        }
    }    

我的做法中使用二维数组记录信任关系,而uwi使用一维数组记录信任或被信任的个数,减少空间占用,代码也更为简洁。

 

999. 车的可用捕获量

在一个 8 x 8 的棋盘上,有一个白色车(rook)。也可能有空方块,白色的象(bishop)和黑色的卒(pawn)。它们分别以字符 “R”,“.”,“B” 和 “p” 给出。大写字符表示白棋,小写字符表示黑棋。

车按国际象棋中的规则移动:它选择四个基本方向中的一个(北,东,西和南),然后朝那个方向移动,直到它选择停止、到达棋盘的边缘或移动到同一方格来捕获该方格上颜色相反的卒。另外,车不能与其他友方(白色)象进入同一个方格。

返回车能够在一次移动中捕获到的卒的数量。
 

示例 1:

输入:[[".",".",".",".",".",".",".","."],[".",".",".","p",".",".",".","."],[".",".",".","R",".",".",".","p"],[".",".",".",".",".",".",".","."],[".",".",".",".",".",".",".","."],[".",".",".","p",".",".",".","."],[".",".",".",".",".",".",".","."],[".",".",".",".",".",".",".","."]]
输出:3
解释:
在本例中,车能够捕获所有的卒。

示例 2:

输入:[[".",".",".",".",".",".",".","."],[".","p","p","p","p","p",".","."],[".","p","p","B","p","p",".","."],[".","p","B","R","B","p",".","."],[".","p","p","B","p","p",".","."],[".","p","p","p","p","p",".","."],[".",".",".",".",".",".",".","."],[".",".",".",".",".",".",".","."]]
输出:0
解释:
象阻止了车捕获任何卒。

示例 3:

输入:[[".",".",".",".",".",".",".","."],[".",".",".","p",".",".",".","."],[".",".",".","p",".",".",".","."],["p","p",".","R",".","p","B","."],[".",".",".",".",".",".",".","."],[".",".",".","B",".",".",".","."],[".",".",".","p",".",".",".","."],[".",".",".",".",".",".",".","."]]
输出:3
解释: 
车可以捕获位置 b5,d6 和 f5 的卒。

 

提示:

  1. board.length == board[i].length == 8
  2. board[i][j] 可以是 'R''.''B' 或 'p'
  3. 只有一个格子上存在 board[i][j] == 'R'

 

 我的作答:

class Solution {
    public int numRookCaptures(char[][] board) {
        int ret = 0;
        int x = 0, y = 0;
        // 找车的位置
        for(int i = 0; i < board.length; i++) {
            for(int j = 0; j < board.length; j++) {
                if(board[i][j] == 'R') {
                    x = i;
                    y = j;
                    break;
                }
            }
        }
        // 沿四个方向扩展,找到棋子或走到边时停下,然后判断停下的情况,若是找到卒了则将结果加一
        int[][] dir = {{1,0},{-1,0},{0,1},{0,-1}};
        for(int i = 0; i < dir.length; i++) {
            int j = x + dir[i][0];
            int k = y + dir[i][1];
            while(j>=0 && j<board.length && k>=0 && k<board.length && board[j][k]=='.') {
                j += dir[i][0];
                k += dir[i][1];
            }
            if(j>=0 && j<board.length && k>=0 && k<board.length && board[j][k] == 'p') {
                ret++;
            }
        }
        return ret;
    }
}

 

uwi的作答:

class Solution {
        public int numRookCaptures(char[][] board) {
            int n = 8;
            int[] dr = { 1, 0, -1, 0 };
            int[] dc = { 0, 1, 0, -1 };
            int ct = 0;
            for(int i = 0;i < n;i++){
                for(int j = 0;j < n;j++){
                    if(board[i][j] == 'R'){
                        inner:
                        for(int k = 0;k < 4;k++){
                            for(int r = i+dr[k], c = j+dc[k];
                                    r >= 0 && r < n && c >= 0 && c < n;
                                    r += dr[k], c += dc[k]){
                                if(board[r][c] != '.'){
                                    if(board[r][c] == 'p')ct++;
                                    continue inner;
                                }
                            }
                        }
                    }
                }
            }
            return ct;
        }

跟我思路差不多,inner我没有用过,学习了

 

998. 最大二叉树 II

最大树定义:一个树,其中每个节点的值都大于其子树中的任何其他值。

给出最大树的根节点 root

就像之前的问题那样,给定的树是从表 Aroot = Construct(A))递归地使用下述 Construct(A) 例程构造的:

  • 如果 A 为空,返回 null
  • 否则,令 A[i] 作为 A 的最大元素。创建一个值为 A[i] 的根节点 root
  • root 的左子树将被构建为 Construct([A[0], A[1], ..., A[i-1]])
  • root 的右子树将被构建为 Construct([A[i+1], A[i+2], ..., A[A.length - 1]])
  • 返回 root

请注意,我们没有直接给定 A,只有一个根节点 root = Construct(A).

假设 B 是 A 的副本,并附加值 val。保证 B 中的值是不同的。

返回 Construct(B)

 

示例 1:

输入:root = [4,1,3,null,null,2], val = 5
输出:[5,4,null,1,3,null,null,2]
解释:A = [1,4,2,3], B = [1,4,2,3,5]

示例 2:

输入:root = [5,2,4,null,1], val = 3
输出:[5,2,4,null,1,null,3]
解释:A = [2,1,5,4], B = [2,1,5,4,3]

示例 3:

输入:root = [5,2,3,null,1], val = 4
输出:[5,2,4,null,1,3]
解释:A = [2,1,5,3], B = [2,1,5,3,4]

 

提示:

  1. 1 <= B.length <= 100

我的作答:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode insertIntoMaxTree(TreeNode root, int val) {
        List<Integer> list = new ArrayList<Integer>();
        if(root != null) {
            getList(root, list);
        }
        list.add(val);
        return getNode(list);
    }
    
    public void getList(TreeNode node, List<Integer> list) {
        if(node.left != null) {
            getList(node.left, list);
        }
        list.add(node.val);
        if(node.right != null) {
            getList(node.right, list);
        }
    }
    
    public TreeNode getNode(List<Integer> list) {
        int max = 0;
        for(int i = 0; i < list.size(); i++) {
            if(list.get(i) > list.get(max)) {
                max = i;
            }
        }
        TreeNode node = new TreeNode(list.get(max));
        if(max > 0) {
            List<Integer> leftList = new ArrayList<Integer>();
            for(int i = 0; i < max; i++) {
                leftList.add(list.get(i));
            }
            node.left = getNode(leftList);
        }
        if(max < (list.size()-1)) {
            List<Integer> rightList = new ArrayList<Integer>();
            for(int i = max+1; i < list.size(); i++) {
                rightList.add(list.get(i));
            }
            node.right = getNode(rightList);
        }
        return node;
    }
    
}

 

uwi的作答:

class Solution {
        public TreeNode insertIntoMaxTree(TreeNode root, int val) {
            TreeNode X = new TreeNode(val);
            if(root == null)return X;
            if(root.val < val){
                X.left = root;
                return X;
            }
            dfs(root, X);
            return root;
        }
        
        void dfs(TreeNode root, TreeNode X)
        {
            if(root.right == null || root.right.val < X.val){
                TreeNode Y = root.right;
                root.right = X;
                X.left = Y;
                return;
            }
            dfs(root.right, X);
        }
    }    

我是递归从树变成列表,添加元素之后再递归从列表还原为树,而uwi的做法是直接递归遍历,显然速度会比我的快。其实问题的本质就是根据数字的大小找到新插入的数字的位置。

 

1001. 网格照明

在 N x N 的网格上,每个单元格 (x, y) 上都有一盏灯,其中 0 <= x < N 且 0 <= y < N 。

最初,一定数量的灯是亮着的。lamps[i] 告诉我们亮着的第 i 盏灯的位置。每盏灯都照亮其所在 x 轴、y 轴和两条对角线上的每个正方形(类似于国际象棋中的皇后)。

对于第 i 次查询 queries[i] = (x, y),如果单元格 (x, y) 是被照亮的,则查询结果为 1,否则为 0 。

在每个查询 (x, y) 之后 [按照查询的顺序],我们关闭位于单元格 (x, y) 上或其相邻 8 个方向上(与单元格 (x, y) 共享一个角或边)的任何灯。

返回答案数组 answer。每个值 answer[i] 应等于第 i 次查询 queries[i] 的结果。

 

示例:

输入:N = 5, lamps = [[0,0],[4,4]], queries = [[1,1],[1,0]]
输出:[1,0]
解释: 
在执行第一次查询之前,我们位于 [0, 0] 和 [4, 4] 灯是亮着的。
表示哪些单元格亮起的网格如下所示,其中 [0, 0] 位于左上角:
1 1 1 1 1
1 1 0 0 1
1 0 1 0 1
1 0 0 1 1
1 1 1 1 1
然后,由于单元格 [1, 1] 亮着,第一次查询返回 1。在此查询后,位于 [0,0] 处的灯将关闭,网格现在如下所示:
1 0 0 0 1
0 1 0 0 1
0 0 1 0 1
0 0 0 1 1
1 1 1 1 1
在执行第二次查询之前,我们只有 [4, 4] 处的灯亮着。现在,[1, 0] 处的查询返回 0,因为该单元格不再亮着。

 

提示:

  1. 1 <= N <= 10^9
  2. 0 <= lamps.length <= 20000
  3. 0 <= queries.length <= 20000
  4. lamps[i].length == queries[i].length == 2

我的作答:

class Solution {
    public int[] gridIllumination(int N, int[][] lamps, int[][] queries) {
        int[] ret = new int[queries.length];
        for(int i = 0; i < queries.length; i++) {
            // 遍历查找是否有灯把该处照亮
            for(int j = 0; j < lamps.length; j++) {
                if(lamps[j][0] != -1 && queries[i][0] == lamps[j][0] || queries[i][1] == lamps[j][1]
                        || ((queries[i][0]-lamps[j][0])==(queries[i][1]-lamps[j][1]))
                        || ((queries[i][0]+queries[i][1])==(lamps[j][0]+lamps[j][1]))) {
                    ret[i] = 1;
                    break;
                }
            }
                
            // 关灯
            for(int j = 0; j < lamps.length; j++) {
                if(Math.abs(queries[i][0]-lamps[j][0])<=1 && Math.abs(queries[i][1]-lamps[j][1])<=1) {
                    lamps[j][0] = -1;
                    lamps[j][1] = -1;
                }
            }
        }
        return ret;
    }
}

 

uwi的作答:

class Solution {
        public int[] gridIllumination(int N, int[][] lamps, int[][] queries) {
            Map<Integer, Integer> lr = new HashMap<>();
            Map<Integer, Integer> lc = new HashMap<>();
            Map<Integer, Integer> ldd = new HashMap<>(); // r-c
            Map<Integer, Integer> ldu = new HashMap<>(); // r+c
            Set<Long> set = new HashSet<>();
            for(int[] l : lamps){
                add(lr, l[0], 1);
                add(lc, l[1], 1);
                add(ldd, l[0]-l[1], 1);
                add(ldu, l[0]+l[1], 1);
                set.add((long)l[0]+1<<32|l[1]+1);
            }
            
            int[] ret = new int[queries.length];
            int p = 0;
            for(int[] q : queries){
                if(lr.containsKey(q[0]) ||
                        lc.containsKey(q[1]) ||
                        ldd.containsKey(q[0]-q[1]) ||
                        ldu.containsKey(q[0]+q[1])
                        ){
                    ret[p] = 1;
                }
                
                for(int k = -1;k <= 1;k++){
                    for(int l = -1;l <= 1;l++){
                        if(set.contains((long)q[0]+k+1<<32|q[1]+l+1)){
                            set.remove((long)q[0]+k+1<<32|q[1]+l+1);
                            int r = q[0]+k, c = q[1]+l;
                            add(lr, r, -1);
                            add(lc, c, -1);
                            add(ldd, r-c, -1);
                            add(ldu, r+c, -1);
                        }
                    }
                }
                
                p++;
            }
            return ret;
        }
        
        void add(Map<Integer, Integer> map, int key, int v)
        {
            int nv = 0;
            if(map.containsKey(key)){
                nv = map.get(key) + v;
            }else{
                nv = v;
            }
            if(nv == 0){
                map.remove(key);
            }else{
                map.put(key, nv);
            }
        }
    }    

这个我觉得我的做法并不比uwi的差,因为是否被照亮根据灯的坐标就能判断出来,并不需要缓存。只能说他这个是空间换时间吧,他的复杂度是O(lamps.length)+O(queries.length),我的是O(lamps.length)*O(queries.length),而且他add方法里的数据结构处理虽然不说很巧妙,但还是比较实用的。



 

转载于:https://www.cnblogs.com/jiang-s/p/10461060.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值