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);
}
*/
}