周赛337(模拟、回溯、同余分组)

周赛337

6319. 奇偶位数

难度简单0

给你一个 整数 n

even 表示在 n 的二进制形式(下标从 0 开始)中值为 1 的偶数下标的个数。

odd 表示在 n 的二进制形式(下标从 0 开始)中值为 1 的奇数下标的个数。

返回整数数组 answer ,其中 answer = [even, odd]

示例 1:

输入:n = 17
输出:[2,0]
解释:17 的二进制形式是 10001 。 
下标 0 和 下标 4 对应的值为 1 。 
共有 2 个偶数下标,0 个奇数下标。

示例 2:

输入:n = 2
输出:[0,1]
解释:2 的二进制形式是 10 。 
下标 1 对应的值为 1 。 
共有 0 个偶数下标,1 个奇数下标。

提示:

  • 1 <= n <= 1000

模拟

class Solution {
    public int[] evenOddBit(int n) {
        int time = 0;
        int[] res = new int[2];
        while(n > 0){
            int i = n % 2;
            time++;
            if(i == 1) res[1 - time % 2]++;
            n /= 2;
        }
        return res;
    }
}

优雅写法:

n&1,取最低比特位

n >>= 1

class Solution {
    public int[] evenOddBit(int n) {
        // i ^= 1 代替变量%2
        var ans = new int[2];
        for (int i = 0; n > 0; i ^= 1, n >>= 1)
            ans[i] += n & 1;
        return ans;
    }
}

6322. 检查骑士巡视方案

难度中等0

骑士在一张 n x n 的棋盘上巡视。在有效的巡视方案中,骑士会从棋盘的 左上角 出发,并且访问棋盘上的每个格子 恰好一次

给你一个 n x n 的整数矩阵 grid ,由范围 [0, n * n - 1] 内的不同整数组成,其中 grid[row][col] 表示单元格 (row, col) 是骑士访问的第 grid[row][col] 个单元格。骑士的行动是从下标 0 开始的。

如果 grid 表示了骑士的有效巡视方案,返回 true;否则返回 false

注意,骑士行动时可以垂直移动两个格子且水平移动一个格子,或水平移动两个格子且垂直移动一个格子。下图展示了骑士从某个格子出发可能的八种行动路线。
img

示例 1:

img

输入:grid = [[0,11,16,5,20],[17,4,19,10,15],[12,1,8,21,6],[3,18,23,14,9],[24,13,2,7,22]]
输出:true
解释:grid 如上图所示,可以证明这是一个有效的巡视方案。

示例 2:

img

输入:grid = [[0,3,6],[5,8,1],[2,7,4]]
输出:false
解释:grid 如上图所示,考虑到骑士第 7 次行动后的位置,第 8 次行动是无效的。

提示:

  • n == grid.length == grid[i].length
  • 3 <= n <= 7
  • 0 <= grid[row][col] < n * n
  • grid 中的所有整数 互不相同

排列型回溯(BFS)

class Solution {
    int[][] dict = new int[][]{{2, 1}, {-2, 1}, {2, -1}, {-2, -1}, {1, 2}, {1, -2}, {-1, 2}, {-1, -2}};
    public boolean checkValidGrid(int[][] grid) {
        if(grid[0][0] != 0) return false;
        int n = grid.length, m = grid[0].length;
        Deque<int[]> dq = new ArrayDeque<>();
        dq.addLast(new int[]{0, 0, 0});
        int cnt = 0; // 访问的格子数
        while(!dq.isEmpty()){
            int[] x = dq.poll();
            cnt++;
            for(int[] d : dict){
                int nx = x[0] + d[0], ny = x[1] + d[1];
                if(nx >= 0 && nx < n && ny >= 0 && ny < n && grid[nx][ny] == x[2]+1)
                    dq.addLast(new int[]{nx, ny, grid[nx][ny]});
            }
        }
        return cnt == n*m;
    }
}

6352. 美丽子集的数目

难度中等5

给你一个由正整数组成的数组 nums 和一个 整数 k

如果 nums 的子集中,任意两个整数的绝对差均不等于 k ,则认为该子数组是一个 美丽 子集。

返回数组 nums非空美丽 的子集数目。

nums 的子集定义为:可以经由 nums 删除某些元素(也可能不删除)得到的一个数组。只有在删除元素时选择的索引不同的情况下,两个子集才会被视作是不同的子集。

示例 1:

输入:nums = [2,4,6], k = 2
输出:4
解释:数组 nums 中的美丽子集有:[2], [4], [6], [2, 6] 。
可以证明数组 [2,4,6] 中只存在 4 个美丽子集。

示例 2:

输入:nums = [1], k = 1
输出:1
解释:数组 nums 中的美丽数组有:[1] 。
可以证明数组 [1] 中只存在 1 个美丽子集。 

提示:

  • 1 <= nums.length <= 20
  • 1 <= nums[i], k <= 1000

子集型回溯变体

答案的角度:枚举i位置选哪个

class Solution {
    int[] nums;
    int k;
    Set<Integer> set = new HashSet<>();
    int res = -1; // 排除空集
    public int beautifulSubsets(int[] nums, int k) {
        // 不要求连续 枚举所有子集,在枚举过程中加个判断
        // 在选择 x = nums[i] 的时候 若之前选过x-k 或者 x+k,就不选了
        this.nums = nums; this.k = k;
        dfs(0);
        return res;
    }

    public void dfs(int idx){
        res++;
        if(idx == nums.length){
            return;
        }
        for(int j = idx; j < nums.length; j++){
            int x = nums[j];
            if(set.contains(x-k) || set.contains(x+k)) continue;
            set.add(x);
            dfs(j+1);
            set.remove(x);
        }
    }
}

输入的角度:选i还是不选

class Solution {
    int[] nums;
    int k;
    Set<Integer> set = new HashSet<>();
    int res = -1; // 排除空集
    public int beautifulSubsets(int[] nums, int k) {
        // 不要求连续 枚举所有子集,在枚举过程中加个判断
        // 在选择 x = nums[i] 的时候 若之前选过x-k 或者 x+k,就不选了
        this.nums = nums; this.k = k;
        dfs(0);
        return res;
    }

    public void dfs(int idx){
        if(idx == nums.length){
            res++;
            return;
        }
        // 不选
        dfs(idx + 1);
        // 选,要先判断一下
        int x = nums[idx];
        if(!set.contains(x-k) && !set.contains(x+k)){
            set.add(x);
            dfs(idx+1);
            set.remove(x);
        }
    }
}

动态规划【✨】


6321. 执行操作后的最大 MEX

难度中等2

给你一个下标从 0 开始的整数数组 nums 和一个整数 value

在一步操作中,你可以对 nums 中的任一元素加上或减去 value

  • 例如,如果 nums = [1,2,3]value = 2 ,你可以选择 nums[0] 减去 value ,得到 nums = [-1,2,3]

数组的 MEX (minimum excluded) 是指其中数组中缺失的最小非负整数。

  • 例如,[-1,2,3] 的 MEX 是 0 ,而 [1,0,3] 的 MEX 是 2

返回在执行上述操作 任意次 后,nums 的最大 MEX

示例 1:

输入:nums = [1,-10,7,13,6,8], value = 5
输出:4
解释:执行下述操作可以得到这一结果:
- nums[1] 加上 value 两次,nums = [1,0,7,13,6,8]
- nums[2] 减去 value 一次,nums = [1,0,2,13,6,8]
- nums[3] 减去 value 两次,nums = [1,0,2,3,6,8]
nums 的 MEX 是 4 。可以证明 4 是可以取到的最大 MEX 。

示例 2:

输入:nums = [1,-10,7,13,6,8], value = 7
输出:2
解释:执行下述操作可以得到这一结果:
- nums[2] 减去 value 一次,nums = [1,-10,0,13,6,8]
nums 的 MEX 是 2 。可以证明 2 是可以取到的最大 MEX 。

提示:

  • 1 <= nums.length, value <= 105
  • -109 <= nums[i] <= 109

同余分组

题解:https://leetcode.cn/problems/smallest-missing-non-negative-integer-after-operations/solution/tong-yu-pythonjavacgo-by-endlesscheng-qoan/

同余:如果(x-y) mod m = 0,那么称xy对模m同余

class Solution {
    public int findSmallestInteger(int[] nums, int m) {
        // 对于最终的数组,能否操作出一个0?
        // 对于最终的数组,能否操作出一个1?
        // ...
        // 取余
        // 统计余数出现的次数,从0到最大MEX依次枚举,制造不出res就是答案
        var cnt = new HashMap<Integer, Integer>();
        for(int x : nums){
            cnt.merge((x % m + m) % m, 1, Integer::sum); // cnt[(x%m+m)%m]++
            // 等同于 cnt.put((x%m+m)%m, cnt.getOrDefault((x%m+m)%m,0)+1);
        }
        int mex = 0;
        while (cnt.merge(mex % m, -1, Integer::sum) >= 0) // cnt[mex%m]-1 >= 0
           ++mex;
        // 等同于:
        // while(cnt.getOrDefault(mex%m, 0) > 0){
        //     cnt.put((mex%m+m)%m, cnt.getOrDefault((mex%m+m)%m,0)-1);
        //     ++mex;
        // }
        return mex;
    }
}
}
    int mex = 0;
    while (cnt.merge(mex % m, -1, Integer::sum) >= 0) // cnt[mex%m]-1 >= 0
       ++mex;
    // 等同于:
    // while(cnt.getOrDefault(mex%m, 0) > 0){
    //     cnt.put((mex%m+m)%m, cnt.getOrDefault((mex%m+m)%m,0)-1);
    //     ++mex;
    // }
    return mex;
}

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值