周赛379(排序、分类讨论、记忆化搜索(动态规划))

这篇具有很好参考价值的文章主要介绍了周赛379(排序、分类讨论、记忆化搜索(动态规划))。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

周赛379

3000. 对角线最长的矩形的面积

简单

给你一个下标从 0 开始的二维整数数组 dimensions

对于所有下标 i0 <= i < dimensions.length),dimensions[i][0] 表示矩形 i 的长度,而 dimensions[i][1] 表示矩形 i 的宽度。

返回对角线最 的矩形的 面积 。如果存在多个对角线长度相同的矩形,返回面积最 的矩形的面积。

示例 1:

输入:dimensions = [[9,3],[8,6]]
输出:48
解释:
下标 = 0,长度 = 9,宽度 = 3。对角线长度 = sqrt(9 * 9 + 3 * 3) = sqrt(90) ≈ 9.487。
下标 = 1,长度 = 8,宽度 = 6。对角线长度 = sqrt(8 * 8 + 6 * 6) = sqrt(100) = 10。
因此,下标为 1 的矩形对角线更长,所以返回面积 = 8 * 6 = 48。

示例 2:

输入:dimensions = [[3,4],[4,3]]
输出:12
解释:两个矩形的对角线长度相同,为 5,所以最大面积 = 12。

提示:

  • 1 <= dimensions.length <= 100
  • dimensions[i].length == 2
  • 1 <= dimensions[i][0], dimensions[i][1] <= 100

排序

class Solution {
    public int areaOfMaxDiagonal(int[][] dimensions) {
        Arrays.sort(dimensions, (a, b) -> 
            (b[0]*b[0]+b[1]*b[1]) == (a[0]*a[0]+a[1]*a[1]) ? 
                b[0]*b[1] - a[0]*a[1] :  (b[0]*b[0]+b[1]*b[1]) - (a[0]*a[0]+a[1]*a[1]));
        return dimensions[0][0] * dimensions[0][1];
    }
}

3001. 捕获黑皇后需要的最少移动次数

中等

现有一个下标从 0 开始的 8 x 8 棋盘,上面有 3 枚棋子。

给你 6 个整数 abcdef ,其中:

  • (a, b) 表示白色车的位置。
  • (c, d) 表示白色象的位置。
  • (e, f) 表示黑皇后的位置。

假定你只能移动白色棋子,返回捕获黑皇后所需的最少移动次数。

请注意

  • 车可以向垂直或水平方向移动任意数量的格子,但不能跳过其他棋子。
  • 象可以沿对角线方向移动任意数量的格子,但不能跳过其他棋子。
  • 如果车或象能移向皇后所在的格子,则认为它们可以捕获皇后。
  • 皇后不能移动。

示例 1:

周赛379(排序、分类讨论、记忆化搜索(动态规划)),算法刷题记录,# LC周赛,动态规划,算法

输入:a = 1, b = 1, c = 8, d = 8, e = 2, f = 3
输出:2
解释:将白色车先移动到 (1, 3) ,然后移动到 (2, 3) 来捕获黑皇后,共需移动 2 次。
由于起始时没有任何棋子正在攻击黑皇后,要想捕获黑皇后,移动次数不可能少于 2 次。

示例 2:

周赛379(排序、分类讨论、记忆化搜索(动态规划)),算法刷题记录,# LC周赛,动态规划,算法

输入:a = 5, b = 3, c = 3, d = 4, e = 5, f = 2
输出:1
解释:可以通过以下任一方式移动 1 次捕获黑皇后:
- 将白色车移动到 (5, 2) 。
- 将白色象移动到 (5, 2) 。

提示:

  • 1 <= a, b, c, d, e, f <= 8
  • 两枚棋子不会同时出现在同一个格子上。

分类讨论

https://leetcode.cn/problems/minimum-moves-to-capture-the-queen/

class Solution {
    /**
    答案不是1就是2
    如果车能直接攻击到皇后 -> 1
    如果象能直接攻击到皇后 -> 1
     */
    public int minMovesToCaptureTheQueen(int a, int b, int c, int d, int e, int f) {
        if ((a == e && (c != a || canReach(b, d, f))) || (b == f && (d != b || canReach(a, c, e)))) {
            return 1;
        } else if ((c - e == d - f && (a - e != b - f || canReach(c, a, e))) || (c - e == f - d && (a - e != f - b || canReach(c, a, e)))) {
            return 1;
        } else {
            return 2;
        }
    }

    public boolean canReach(int source, int obstacle, int target) {
        int minPos = Math.min(source, target), maxPos = Math.max(source, target);
        return obstacle < minPos || obstacle > maxPos;
    }
}

3002. 移除后集合的最多元素数

中等

给你两个下标从 0 开始的整数数组 nums1nums2 ,它们的长度都是偶数 n

你必须从 nums1 中移除 n / 2 个元素,同时从 nums2 中也移除 n / 2 个元素。移除之后,你将 nums1nums2 中剩下的元素插入到集合 s 中。

返回集合 s可能的 最多 包含多少元素。

示例 1:

输入:nums1 = [1,2,1,2], nums2 = [1,1,1,1]
输出:2
解释:从 nums1 和 nums2 中移除两个 1 。移除后,数组变为 nums1 = [2,2] 和 nums2 = [1,1] 。因此,s = {1,2} 。
可以证明,在移除之后,集合 s 最多可以包含 2 个元素。

示例 2:

输入:nums1 = [1,2,3,4,5,6], nums2 = [2,3,2,3,2,3]
输出:5
解释:从 nums1 中移除 2、3 和 6 ,同时从 nums2 中移除两个 3 和一个 2 。移除后,数组变为 nums1 = [1,4,5] 和 nums2 = [2,3,2] 。因此,s = {1,2,3,4,5} 。
可以证明,在移除之后,集合 s 最多可以包含 5 个元素。 

示例 3:

输入:nums1 = [1,1,2,2,3,3], nums2 = [4,4,5,5,6,6]
输出:6
解释:从 nums1 中移除 1、2 和 3 ,同时从 nums2 中移除 4、5 和 6 。移除后,数组变为 nums1 = [1,2,3] 和 nums2 = [4,5,6] 。因此,s = {1,2,3,4,5,6} 。
可以证明,在移除之后,集合 s 最多可以包含 6 个元素。 

提示:

  • n == nums1.length == nums2.length
  • 1 <= n <= 2 * 104
  • n是偶数。
  • 1 <= nums1[i], nums2[i] <= 109

分类讨论

https://leetcode.cn/problems/maximum-size-of-a-set-after-removals/solutions/2594380/tan-xin-pythonjavacgo-by-endlesscheng-ymuh/

class Solution {
    /** 从移除的角度思考
    设 nums1 中有 n1 个不同的元素, nums2 中有 n2 个不同元素,他们的交集有 common 个元素
    如果不移除任何元素,nums1 和 nums2 的并集一共有 n1 + n2 - common 个不同元素

    我们可以先移除每个元素中重复的元素,在考虑从剩下的数中移除元素
    设 m = n/2, 对于 nums1 来说,如果 n1 > m, 先从交集中移除元素
        如果交集元素少,那么全部移除, 即移除 common个元素
        如果交集元素多,那么移除交集中的 n1-m 个元素,就可以让 n1 = m
        即从交集中移除 min(n1-m, common) 个元素
    
    移除后,如果n1仍然大于m,则必须把ans 减少 n1-m
     */
    public int maximumSetSize(int[] nums1, int[] nums2) {
        Set<Integer> s1 = new HashSet<>();
        Set<Integer> s2 = new HashSet<>();
        for(int x : nums1) s1.add(x);
        int common = 0;
        for(int x : nums2){
            // 判断两个set有多少个重叠的元素
            if(s2.add(x) && s1.contains(x)){
                common++;
            }
        }
        int n1 = s1.size();
        int n2 = s2.size();
        int ans = n1 + n2 - common;
        int m = nums1.length / 2;
        if(n1 > m){ // 先从交集中移除元素
            // 只移除交集元素时,最多能移除 mn 个
            int mn = Math.min(n1 - m, common);
            n1 -= mn;
            common -= mn;
            // 移除后,如果n1仍然大于m,则必须把ans 减少 n1-m 
            ans -= n1 - m; // 从集合1中取走元素
        }
        if(n2 > m){
            n2 -=  Math.min(n2 - m, common);
            ans -= n2 - m;
        }
        return ans;
    }
}

3003. 执行操作后的最大分割数量

困难

给你一个下标从 0 开始的字符串 s 和一个整数 k

你需要执行以下分割操作,直到字符串 s 变为

  • 选择 s 的最长前缀,该前缀最多包含 k 不同 字符。
  • 删除 这个前缀,并将分割数量加一。如果有剩余字符,它们在 s 中保持原来的顺序。

执行操作之 ,你可以将 s至多一处 下标的对应字符更改为另一个小写英文字母。

在最优选择情形下改变至多一处下标对应字符后,用整数表示并返回操作结束时得到的最大分割数量。

示例 1:

输入:s = "accca", k = 2
输出:3
解释:在此示例中,为了最大化得到的分割数量,可以将 s[2] 改为 'b'。
s 变为 "acbca"。
按照以下方式执行操作,直到 s 变为空:
- 选择最长且至多包含 2 个不同字符的前缀,"acbca"。
- 删除该前缀,s 变为 "bca"。现在分割数量为 1。
- 选择最长且至多包含 2 个不同字符的前缀,"bca"。
- 删除该前缀,s 变为 "a"。现在分割数量为 2。
- 选择最长且至多包含 2 个不同字符的前缀,"a"。
- 删除该前缀,s 变为空。现在分割数量为 3。
因此,答案是 3。
可以证明,分割数量不可能超过 3。

示例 2:

输入:s = "aabaab", k = 3
输出:1
解释:在此示例中,为了最大化得到的分割数量,可以保持 s 不变。
按照以下方式执行操作,直到 s 变为空: 
- 选择最长且至多包含 3 个不同字符的前缀,"aabaab"。
- 删除该前缀,s 变为空。现在分割数量为 1。
因此,答案是 1。
可以证明,分割数量不可能超过 1。

示例 3:

输入:s = "xxyz", k = 1
输出:4
解释:在此示例中,为了最大化得到的分割数量,可以将 s[1] 改为 'a'。
s 变为 "xayz"。
按照以下方式执行操作,直到 s 变为空:
- 选择最长且至多包含 1 个不同字符的前缀,"xayz"。
- 删除该前缀,s 变为 "ayz"。现在分割数量为 1。
- 选择最长且至多包含 1 个不同字符的前缀,"ayz"。
- 删除该前缀,s 变为 "yz",现在分割数量为 2。
- 选择最长且至多包含 1 个不同字符的前缀,"yz"。
- 删除该前缀,s 变为 "z"。现在分割数量为 3。
- 选择最且至多包含 1 个不同字符的前缀,"z"。
- 删除该前缀,s 变为空。现在分割数量为 4。
因此,答案是 4。
可以证明,分割数量不可能超过 4。

提示:

  • 1 <= s.length <= 104
  • s 只包含小写英文字母。
  • 1 <= k <= 26

记忆化搜索(动态规划)

https://leetcode.cn/problems/maximize-the-number-of-partitions-after-operations/solutions/2595072/ji-yi-hua-sou-suo-jian-ji-xie-fa-pythonj-6g5z/文章来源地址https://www.toymoban.com/news/detail-806242.html

class Solution {
    char[] s;
    int k;
    Map<Long, Integer> memo;
    public int maxPartitionsAfterOperations(String S, int k) {
        memo = new HashMap<>();
        this.k = k;
        this.s = S.toCharArray();
        return dfs(0, 0, 0);
    }
    /**
    定义 dfs(i, mask, changed) 表示当前遍历到s[i],当前这一段在i之前的字符集合是mask,
                                    是否已经修改了字符(changed),后续得到的最大分割数
    讨论是否修改s[i],以及当前字母能否加到mask中
    如果不改 s[i]:
        如果s[i]加到mask后,集合的大小超过了k,那么s[i]必须划分到下一段子串中,答案为dfs(i+1,{s[i]},changed)+1
        如果s[i]加到mask后,集合的大小没有超过k,那么s[i]必须划分到这一段中,答案为dfs(i+1,mask∪{s[i]},changed)
    如果changed=false,那么可以修改s[i],枚举改成第j个字母
        如果j加到mask后,集合大小超过了k,那么j必须划分到下一段子串中,答案为dfs(i+1, {j}, true)+1
        如果j加到mask后,集合大小没有超过k,那么j必须划分到这一段中,答案为dfs(i+1,mask∪ {j}, true)
    以上情况取最大值
    递归边界dfs(n,*,*)=1
    递归入口dfs(0, 0, false)
     */
    private int dfs(int i, int mask, int changed){
        if(i == s.length)
            return 1;
        long argsMask = (long) i << 32 | mask << 1 | changed;
        if (memo.containsKey(argsMask)) { // 之前计算过
            return memo.get(argsMask);
        }
        int res;
        // 不改s[i]
        int bit = 1 << (s[i] - 'a');
        int newMask = mask | bit;
        if(Integer.bitCount(newMask) > k){
            // 分割出一个子串,这个子串的最后一个字母在 i-1
            // s[i] 作为下一段的第一个字母,也就是 bit 作为下一段的 mask 的初始值
            res = dfs(i+1, bit, changed) + 1;
        }else{ // 不分割
            res = dfs(i+1, newMask, changed);
        }
        // 改s[i]
        if(changed == 0){
            // 枚举把 s[i] 改成 a,b,c,...,z
            for (int j = 0; j < 26; j++) {
                newMask = mask | (1 << j);
                if (Integer.bitCount(newMask) > k) {
                    // 分割出一个子串,这个子串的最后一个字母在 i-1
                    // j 作为下一段的第一个字母,也就是 1<<j 作为下一段的 mask 的初始值
                    res = Math.max(res, dfs(i + 1, 1 << j, 1) + 1);
                } else { // 不分割
                    res = Math.max(res, dfs(i + 1, newMask, 1));
                }
            }
        }
        memo.put(argsMask, res); // 记忆化
        return res;
    }
}

到了这里,关于周赛379(排序、分类讨论、记忆化搜索(动态规划))的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【动态规划】【记忆化搜索】C++算法:546移除盒子

    视频算法专题 动态规划汇总 记忆化搜索 给出一些不同颜色的盒子 boxes ,盒子的颜色由不同的正数表示。 你将经过若干轮操作去去掉盒子,直到所有的盒子都去掉为止。每一轮你可以移除具有相同颜色的连续 k 个盒子(k = 1),这样一轮之后你将得到 k * k 个积分。 返回 你能

    2024年01月16日
    浏览(35)
  • 【LeetCode:64. 最小路径和 | 暴力递归=>记忆化搜索=>动态规划 】

    🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,CSDN-Java领域新星创作者🏆,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文

    2024年02月05日
    浏览(44)
  • 【动态规划】【记忆化搜索】【状态压缩】1681. 最小不兼容性

    【数位dp】【动态规划】【状态压缩】【推荐】1012. 至少有 1 位重复的数字 动态规划汇总 状态压缩 记忆化搜索 给你一个整数数组 nums​​​ 和一个整数 k 。你需要将这个数组划分到 k 个相同大小的子集中,使得同一个子集里面没有两个相同的元素。 一个子集的 不兼容性 是

    2024年02月19日
    浏览(39)
  • 【动态规划】【记忆化搜索】【C++算法】664. 奇怪的打印机

    视频算法专题 动态规划汇总 记忆化搜索 字符串 有台奇怪的打印机有以下两个特殊要求: 打印机每次只能打印由 同一个字符 组成的序列。 每次可以在从起始到结束的任意位置打印新字符,并且会覆盖掉原来已有的字符。 给你一个字符串 s ,你的任务是计算这个打印机打印

    2024年01月21日
    浏览(34)
  • 【数学】【记忆化搜索 】【动态规划】964. 表示数字的最少运算符

    【动态规划】【字符串】【表达式】2019. 解出数学表达式的学生分数 动态规划汇总 数学 记忆化搜索 给定一个正整数 x,我们将会写出一个形如 x (op1) x (op2) x (op3) x … 的表达式,其中每个运算符 op1,op2,… 可以是加、减、乘、除(+,-,*,或是 /)之一。例如,对于 x = 3,

    2024年02月22日
    浏览(48)
  • 【LeetCode: 44. 通配符匹配 | 暴力递归=>记忆化搜索=>动态规划 】

    🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,CSDN-Java领域优质创作者🏆,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文

    2024年02月06日
    浏览(73)
  • 上升子序列的最大长度,递归-记忆化搜索-动态规划三步走

    题目描述: 小明有一个数组,他想从数组任意元素开始向后遍历,找出所有上升子序列,并计算出最长的上升子序列的长度。 数据范围: 每组数据长度满足 1≤n≤200 1≤n≤200 , 数据大小满足 1≤val≤350 1≤val≤350 输入描述: 数据共2行,第1行先输入数组的个数,第2行再输

    2024年04月22日
    浏览(41)
  • 【LeetCode: 53. 最大子数组和 | 暴力递归=>记忆化搜索=>动态规划 | 分治法 】

    🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,CSDN-Java领域新星创作者🏆,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文

    2023年04月21日
    浏览(84)
  • 【LeetCode: 410. 分割数组的最大值 | 暴力递归=>记忆化搜索=>动态规划 】

    🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,CSDN-Java领域优质创作者🏆,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文

    2024年02月10日
    浏览(42)
  • 【LeetCode: 97. 交错字符串 | 暴力递归=>记忆化搜索=>动态规划 | 位置对应】

    🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,CSDN-Java领域优质创作者🏆,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文

    2024年02月05日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包