LeetCode 1001. 网格照明 / 2006. 差的绝对值为 K 的数对数目 / 1447. 最简分数

1001. 网格照明

2022.2.08 每日一题

题目描述

在大小为 n x n 的网格 grid 上,每个单元格都有一盏灯,最初灯都处于 关闭 状态。

给你一个由灯的位置组成的二维数组 lamps ,其中 lamps[i] = [rowi, coli] 表示 打开 位于 grid[rowi][coli] 的灯。即便同一盏灯可能在 lamps 中多次列出,不会影响这盏灯处于 打开 状态。

当一盏灯处于打开状态,它将会照亮 自身所在单元格 以及同一 行 、同一 列 和两条 对角线 上的 所有其他单元格 。

另给你一个二维数组 queries ,其中 queries[j] = [rowj, colj] 。对于第 j 个查询,如果单元格 [rowj, colj] 是被照亮的,则查询结果为 1 ,否则为 0 。在第 j 次查询之后 [按照查询的顺序] ,关闭 位于单元格 grid[rowj][colj] 上及相邻 8 个方向上(与单元格 grid[rowi][coli] 共享角或边)的任何灯。

返回一个整数数组 ans 作为答案, ans[j] 应等于第 j 次查询 queries[j] 的结果,1 表示照亮,0 表示未照亮。

示例 1:

在这里插入图片描述
输入:n = 5, lamps = [[0,0],[4,4]], queries = [[1,1],[1,0]]
输出:[1,0]
解释:最初所有灯都是关闭的。在执行查询之前,打开位于 [0, 0] 和 [4, 4] 的灯。第 0 次查询检查 grid[1][1] 是否被照亮(蓝色方框)。该单元格被照亮,所以 ans[0] = 1 。然后,关闭红色方框中的所有灯。
在这里插入图片描述
第 1 次查询检查 grid[1][0] 是否被照亮(蓝色方框)。该单元格没有被照亮,所以 ans[1] = 0 。然后,关闭红色矩形中的所有灯。
在这里插入图片描述

示例 2:

输入:n = 5, lamps = [[0,0],[4,4]], queries = [[1,1],[1,1]]
输出:[1,1]

示例 3:

输入:n = 5, lamps = [[0,0],[0,4]], queries = [[0,4],[0,1],[1,4]]
输出:[1,1,0]

提示:

1 <= n <= 10^9
0 <= lamps.length <= 20000
0 <= queries.length <= 20000
lamps[i].length == 2
0 <= rowi, coli < n
queries[j].length == 2
0 <= rowj, colj < n

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/grid-illumination
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

主要问题就是怎么表示对角线

class Solution {
    int[][] dir = {{0, 0}, {0,1}, {0, -1}, {1,0}, {-1, 0}, {-1, -1}, {1, -1}, {1, 1}, {-1, 1}};
    public int[] gridIllumination(int n, int[][] lamps, int[][] queries) {
        //想想该怎么记录
        //如果单纯是行和列的话,就可以简单记录每一行一列被照亮的次数
        //然后查询的时候,看这个地方是否被照亮,然后查找这个位置附近的灯,把它熄灭,然后从哈希表中减去
        //有对角线的话,应该怎么表示对角线呢,主对角线从右上角开始记录,副对角线从左上角开始记录
        //主副对角线有2n - 1条
        //怎么统计主对角线和副对角线呢,发现主对角线的特点,i - j 是固定值
        //副对角线,i + j是固定值,这样就可以记录了
        
        int ll = lamps.length;
        int lq = queries.length;

        Map<Integer, Integer> row = new HashMap<>();
        Map<Integer, Integer> col = new HashMap<>();
        Map<Integer, Integer> first = new HashMap<>();      //主对角线
        Map<Integer, Integer> sec = new HashMap<>();        //副对角线

        Set<Long> set = new HashSet<>();     //记录亮灯的地方
        for(int i = 0; i < ll; i++){
            int[] temp = lamps[i];
            
            long idx = temp[0] * 1000000001 + temp[1];
            if(set.contains(idx))
                continue;
            set.add(idx);
            int t1 = temp[0] + temp[1];
            int t2 = temp[0] - temp[1];
            row.put(temp[0], row.getOrDefault(temp[0], 0) + 1);
            col.put(temp[1], col.getOrDefault(temp[1], 0) + 1);
            first.put(t2, first.getOrDefault(t2, 0) + 1);
            sec.put(t1, sec.getOrDefault(t1, 0) + 1);
        }

        int[] res = new int[lq];
        for(int i = 0; i < lq; i++){
            int[] temp = queries[i];
            int t1 = temp[0] + temp[1];
            int t2 = temp[0] - temp[1];
        
            if(row.getOrDefault(temp[0], 0) > 0 || col.getOrDefault(temp[1], 0) > 0 || first.getOrDefault(t2, 0) > 0 || sec.getOrDefault(t1, 0) > 0)
                res[i] = 1;
            else
                res[i] = 0;
            
            for(int[] d : dir){
                int x = temp[0] + d[0];
                int y = temp[1] + d[1];
                long idx = x * 1000000001 + y;
                if(x < 0 || x >= n || y < 0 || y >= n || !set.contains(idx))
                    continue;
                
                //如果这个位置有灯
                int tt1 = x + y;
                int tt2 = x - y;

                set.remove(idx);
                row.put(x, row.get(x) - 1);
                col.put(y, col.get(y) - 1);
                first.put(tt2, first.get(tt2) - 1);
                sec.put(tt1, sec.get(tt1) - 1);
            }    
        }
        return res;

    }
}

2006. 差的绝对值为 K 的数对数目

2022.2.09 每日一题

题目描述

给你一个整数数组 nums 和一个整数 k ,请你返回数对 (i, j) 的数目,满足 i < j 且 |nums[i] - nums[j]| == k 。

|x| 的值定义为:

如果 x >= 0 ,那么值为 x 。
如果 x < 0 ,那么值为 -x 。

示例 1:

输入:nums = [1,2,2,1], k = 1
输出:4
解释:差的绝对值为 1 的数对为:
-[1,2,2,1]
-[1,2,2,1]
-[1,2,2,1]
-[1,2,2,1]

示例 2:

输入:nums = [1,3], k = 3
输出:0
解释:没有任何数对差的绝对值为 3 。

示例 3:

输入:nums = [3,2,1,5,4], k = 2
输出:3
解释:差的绝对值为 2 的数对为:
-[3,2,1,5,4]
-[3,2,1,5,4]
-[3,2,1,5,4]

提示:

1 <= nums.length <= 200
1 <= nums[i] <= 100
1 <= k <= 99

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/count-number-of-pairs-with-absolute-difference-k
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

暴力

class Solution {
    public int countKDifference(int[] nums, int k) {
        //暴力可以,排序可以吗,好像也行,因为是绝对值等于k
        int res = 0;
        int n = nums.length;
        for(int i = 0; i < n; i++){
            for(int j = i + 1; j < n; j++){
                if(Math.abs(nums[i] - nums[j]) == k)
                    res++;
            }
        }
        return res;
    }
}

因为最多只有100种数,所以相当于计数排序

class Solution {
    public int countKDifference(int[] nums, int k) {
        //暴力可以,排序可以吗,好像也行,因为是绝对值等于k
        int res = 0;
        int n = nums.length;
        int[] count = new int[101];
        for(int i = 0; i < n; i++){
            count[nums[i]]++;
        }
        for(int i = 1; i < 101 - k; i++){
            res += count[i] * count[i + k];
        }
        return res;
    }
}

遍历一次,不知道大家是否会有这种感觉,这样到底对吗,后面添加的数不影响结果吗
其实不会影响的,因为每次遍历到一个数,都会计算这个数当前满足条件的个数,因此每个数都能和它需要匹配的数都匹配过,所以不会错

class Solution {
    public int countKDifference(int[] nums, int k) {
        int[] cnts = new int[110];
        int n = nums.length, ans = 0;
        for (int i = 0; i < n; i++) {
            int t = nums[i];
            if (t - k >= 1) ans += cnts[t - k];
            if (t + k <= 100) ans += cnts[t + k];
            cnts[t]++;
        }
        return ans;
    }
}

1447. 最简分数

2022.2.10 每日一题

题目描述

给你一个整数 n ,请你返回所有 0 到 1 之间(不包括 0 和 1)满足分母小于等于 n 的 最简 分数 。分数可以以 任意 顺序返回。

示例 1:

输入:n = 2
输出:[“1/2”]
解释:“1/2” 是唯一一个分母小于等于 2 的最简分数。

示例 2:

输入:n = 3
输出:[“1/2”,“1/3”,“2/3”]

示例 3:

输入:n = 4
输出:[“1/2”,“1/3”,“1/4”,“2/3”,“3/4”]
解释:“2/4” 不是最简分数,因为它可以化简为 “1/2” 。

示例 4:

输入:n = 1
输出:[]

提示:

1 <= n <= 100

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/simplified-fractions
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

主要问题是判断两个数是否有公因数

class Solution {
    public List<String> simplifiedFractions(int n) {
        //相当于分子分母没有除1以外的公因数
        //如何判断两个数是否有公因数
        
        List<String> res = new ArrayList<>();

        for(int i = 2; i <= n; i++){
            for(int j = 1; j < i; j++){
                //如果他俩没有公因数
                if(!judge(i, j)){
                    String temp = j + "/" + i;
                    res.add(temp);
                }
            }
        }
        return res;
    }   
    public boolean judge(int i, int j){
        for(int t = 2; t <= j; t++){
            if(i % t == 0 && j % t == 0)
                return true;
        }
        return false;
    }
}

辗转相除法

class Solution {
    public List<String> simplifiedFractions(int n) {
        //相当于分子分母没有除1以外的公因数
        //如何判断两个数是否有公因数
        
        List<String> res = new ArrayList<>();

        for(int i = 2; i <= n; i++){
            for(int j = 1; j < i; j++){
                //如果他俩没有公因数
                if(judge(i, j) == 1){
                    String temp = j + "/" + i;
                    res.add(temp);
                }
            }
        }
        return res;
    }   

    //写一下辗转相除法
    public int judge(int i, int j){
        while(i % j != 0){
            int yu = i % j;
            i = j;
            j = yu;
        }
        return j;
    }
	//递归形式
	/*
	public int judge(int i, int j){
        return i % j == 0 ? j : judge(j, i % j);
    }
	*/
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值