左神高阶进阶班4 (尼姆博弈问题、k伪进制、递归到动态规划、优先级结合的递归套路、子串的递归套路,子序列的递归套路,动态规划的压缩技巧)

news2024/11/18 19:34:16

目录

【案例1  尼姆博弈问题】

【题目描述】

【思路解析】

【代码实现】

【案例2   k伪进制问题】

【题目描述】

【思路解析】

【代码实现】

【案例3   最大路径和】

【题目描述】

【思路解析】

【代码实现】

【案例4 优先级的递归套路】

【题目描述】

 【思路解析】

【代码实现】

【案例5  子串的递归套路 动态规划的空间压缩技巧】

【题目描述】

 【思路解析】

【代码实现】

【案例6 子序列的递归问题】

【问题描述】

 【思路解析】

【代码实现】


大家觉得写得可以的话,可以加入QQ群907575059.

【案例1  尼姆博弈问题】

【题目描述】

【思路解析】

异或和 指初始情况下,所有的铜板堆数量的异或和。

如果有1堆铜板,先手必赢,此时异或和不为0.

如果有2堆铜板,(1)两堆铜板数量相同,先手必输,此时异或和为0(2)两堆铜板数量不同,先手必胜,此时异或和不为0.

如果继续下去,我们可以发现我们最后怎么才能赢,就是拿过之后,必须保证异或和为0。当拿空时,异或和也为0。所以可以得出结论,当初始时异或和不为0,先手赢,但是如果硬币异或和不为0,后手赢。

【代码实现】

/**
 * @ProjectName: study3
 * @FileName: Ex1
 * @author:HWJ
 * @Data: 2023/9/23 16:46
 * 尼姆博弈问题
 */
public class Ex1 {
    public static void main(String[] args) {
        
    }
    
    public static void getWin(int[] num){
        int xor = num[0];
        for (int i = 1; i < num.length; i++) {
            xor ^= num[i];
        }
        if (xor == 0){
            System.out.println("后手赢!");
        }else {
            System.out.println("先手赢!");
        }
    }
}

【案例2   k伪进制问题】

【题目描述】

【思路解析】

k伪进制和k进制的区别就在于它每个位置上必须有值,值的范围在 [1,k]之间,所以有个普遍想法就是先开始每个位置上尽量放1(从右至左),直到放不了了,然后从那个位置开始往右重新填数。

假如将103用7伪进制表示:1 1 1,只能填三个位置,剩下46,然后用这三个位置继续表示46即可。

【代码实现】

package AdvancedPromotion4;

import java.util.HashMap;

/**
 * @ProjectName: study3
 * @FileName: Ex2
 * @author:HWJ
 * @Data: 2023/9/23 16:56
 */
public class Ex2 {
    public static void main(String[] args) {
        char[] chars = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
        kConversion(123, chars);
    }

    public static void kConversion(int num, char[] chars) {
        int len = chars.length;
        HashMap<Integer, Integer> map = new HashMap<>();
        int max = 0;
        for (int i = 0; Math.pow(len, i) <= num; i++) {
            num -= (int) Math.pow(len, i);
            map.put(i, 1);
            max = i;
        }
        for (int i = max; i >= 0; i--) {
            int a = num / (int) Math.pow(len, i);
            num %= (int) Math.pow(len, i);
            map.put(i, map.get(i) + a);
        }
        StringBuilder str = new StringBuilder();
        for (int i = max; i >= 0; i--) {
            str.append(chars[map.get(i) - 1]);
        }
        System.out.println(str);
    }

}

【案例3   最大路径和】

【题目描述】

【思路解析】

它不一定要达到最右边才会得到它的最长长度,即它可能在二维数组的任一位置得到最长长度。遍历数组每一个位置得到信息(包括没使用能力的最大长度,和使用能力的最大长度)。

但是每个位置又依靠它的左上位置,,左位置,左下位置,则需要使用递归。可以改为记忆化搜索和动态规划的版本。此题因为不存在枚举行为,所以记忆化搜索和动态规划的时间复杂度和空间复杂度相似。

【代码实现】

package AdvancedPromotion4;

/**
 * @ProjectName: study3
 * @FileName: Ex3
 * @author:HWJ
 * @Data: 2023/9/23 20:12
 */
public class Ex3 {
    public static void main(String[] args) {
        int[][] matrix = {{1, -4, 10}, {3, -2, -1}, {2, -1, 0}, {0, 5, -2}};
        System.out.println(getMaxLength1(matrix));
    }

    public static class Info {
        public int use;
        public int no;

        public Info(int no, int use) {
            this.use = use;
            this.no = no;
        }
    }

    // 递归版本
    public static int getMaxLength1(int[][] matrix) {
        int res = Integer.MIN_VALUE;
        for (int j = 0; j < matrix[0].length; j++) {
            for (int i = 0; i < matrix.length; i++) {
                Info cur = process1(matrix, i, j);
                int ans = Math.max(cur.no, cur.use);
                res = Math.max(ans, res);

            }
        }
        return res;
    }


    // 递归版本
    public static Info process1(int[][] matrix, int i, int j) {
        if (j == 0) {
            return new Info(matrix[i][j], -matrix[i][j]);
        }
        int preNo = -1;
        int preUse = -1;
        Info preLeft = process1(matrix, i, j - 1);
        if (preLeft.no >= 0) {
            preNo = preLeft.no;
        }
        if (preLeft.use >= 0) {
            preUse = preLeft.use;
        }


        if (i > 0) {
            Info preUp = process1(matrix, i - 1, j - 1);
            if (preUp.no >= 0) {
                preNo = Math.max(preUp.no, preNo);
            }
            if (preUp.use >= 0) {
                preUse = Math.max(preUse, preUp.use);
            }
        }

        if (i < matrix.length - 1) {
            Info preDown = process1(matrix, i + 1, j - 1);
            if (preDown.no >= 0) {
                preNo = Math.max(preDown.no, preNo);
            }
            if (preDown.use >= 0) {
                preUse = Math.max(preUse, preDown.use);
            }
        }
        int use = -1;
        int no = -1;
        if (preUse >= 0) {
            use = preUse + matrix[i][j];
        }
        if (preNo >= 0) {
            no = preNo + matrix[i][j];
            use = Math.max(use, preNo - matrix[i][j]);
        }
        return new Info(no, use);
    }

    // 记忆化搜索版本
    public static int getMaxLength2(int[][] matrix) {
        int res = Integer.MIN_VALUE;
        Info[][] map = new Info[matrix.length][matrix[0].length];
        for (int j = 0; j < matrix[0].length; j++) {
            for (int i = 0; i < matrix.length; i++) {
                Info cur = process2(matrix, i, j, map);
                int ans = Math.max(cur.no, cur.use);
                res = Math.max(ans, res);

            }
        }
        return res;
    }

    // 记忆化搜索版本版本
    public static Info process2(int[][] matrix, int i, int j, Info[][] map) {
        if (map[i][j] != null) { // 如果已经得到信息的地方,之间调用之前的信息
            return map[i][j];
        }
        if (j == 0) {
            map[i][j] = new Info(matrix[i][j], -matrix[i][j]);
            return map[i][j];
        }
        int preNo = -1;
        int preUse = -1;
        Info preLeft = process2(matrix, i, j - 1, map);
        if (preLeft.no >= 0) {
            preNo = preLeft.no;
        }
        if (preLeft.use >= 0) {
            preUse = preLeft.use;
        }


        if (i > 0) {
            Info preUp = process2(matrix, i - 1, j - 1, map);
            if (preUp.no >= 0) {
                preNo = Math.max(preUp.no, preNo);
            }
            if (preUp.use >= 0) {
                preUse = Math.max(preUse, preUp.use);
            }
        }

        if (i < matrix.length - 1) {
            Info preDown = process2(matrix, i + 1, j - 1, map);
            if (preDown.no >= 0) {
                preNo = Math.max(preDown.no, preNo);
            }
            if (preDown.use >= 0) {
                preUse = Math.max(preUse, preDown.use);
            }
        }
        int use = -1;
        int no = -1;
        if (preUse >= 0) {
            use = preUse + matrix[i][j];
        }
        if (preNo >= 0) {
            no = preNo + matrix[i][j];
            use = Math.max(use, preNo - matrix[i][j]);
        }
        map[i][j] = new Info(no, use);
        return map[i][j];
    }
}

【案例4 优先级的递归套路】

【题目描述】

 【思路解析】

先用栈实现不含括号的表达式求值,如果遇到运算符,且此时栈顶的运算符不为乘,除,就将运算符之前的数值和运算符加入栈,否则弹出运算符和运算符之前的数值,并且将其和当前数值进行运算后,在再将运算的值和当前运算符加入栈。

实现这个后我们考虑一个信息结构process(str,i)返回两个数值a,b  a表示从i开始到停止地方得到的运算结果,b表示它在哪里停止。遇到右括号或者到边界就停止。

【代码实现】

package AdvancedPromotion4;

import java.util.LinkedList;

/**
 * @ProjectName: study3
 * @FileName: Ex4
 * @author:HWJ
 * @Data: 2023/9/23 20:49
 */
public class Ex4 {
    public static void main(String[] args) {
        String str = "48*((70-65)-43)+8*1";
        System.out.println(getNum(str));
    }

    public static int getNum(String str) {
        return process(str, 0)[0];
    }

    
    // 将每一个括号里面包含的运算式记作为一个整体进行计算。
    public static int[] process(String str, int index) {
        LinkedList<String> list = new LinkedList<>();
        int num = 0;
        while (index < str.length() && str.charAt(index) != ')') {
            if (str.charAt(index) >= '0' && str.charAt(index) <= '9') {
                num = num * 10 + str.charAt(index) - '0';
                index++;
            } else if (str.charAt(index) == '(') {  // 这里遇到左括号
                int[] ans = process(str, index + 1);
                index = ans[1] + 1; // 此次运算的结束位置
                num = ans[0]; // 括号里运算式总体的运算结果。
            } else { // 遇到运算符
                addNum(list, num);
                list.addLast(String.valueOf(str.charAt(index++)));
                num = 0;
            }
        }
        addNum(list, num);
        return new int[]{totalNum(list), index};
    }

    
    // 当栈顶运算符为乘或除时,暂时对运算式进行计算。
    public static void addNum(LinkedList<String> list, int num) {
        if (!list.isEmpty()) {
            int cur = 0;
            String operator = list.pollLast();
            if (operator.equals("+") || operator.equals("-")) {
                list.addLast(operator);
            } else {
                cur = Integer.valueOf(list.pollLast());
                num = operator.equals("*") ? num * cur : cur / num;

            }
        }
        list.addLast(String.valueOf(num));
    }

    
    // 处理完后整个栈里只剩下数值和加减运算符
    public static int totalNum(LinkedList<String> list) {
        int res = 0;
        boolean add = true;
        String cur = null;
        int num = 0;
        while (!list.isEmpty()) {
            cur = list.pollFirst();
            if (cur.equals("+")) {
                add = true;
            }else if(cur.equals("-")){
                add = false;
            }else {
                num = Integer.valueOf(cur);
                res += add ? num : (-num);
            }
        }
        return res;
    }
}

【案例5  子串的递归套路 动态规划的空间压缩技巧】

【题目描述】

 【思路解析】

因为子串一定是在字符串中连续的字符子串。两个字符串的最长公共子串可能以str1的任意位置结尾和str2的任意位置结尾,但是因为是公共子串则要求两个的对应位置字符相同,所以如果str1以i结尾和str2以j结尾的公共子串长度取决于str1以i - 1结尾和str2以j - 1结尾的公共子串长度 + 1.(str1以i结尾和str2以j结尾的字符相同)

根据标红的对应关系可知,dp[i][j]只依赖与dp[i-1][j-1],所以我们可以不必要创建一个二维数组来进行dp。例如如下规则来对动态规划空间进行压缩。

107421
1311853
15141296

以上数字代表优化后的填表技巧,当填3时,我们只记录2,填4时只记录3.将整个表优化为一个变量。

【代码实现】

package AdvancedPromotion4;


/**
 * @ProjectName: study3
 * @FileName: Ex5
 * @author:HWJ
 * @Data: 2023/9/23 21:27
 */
public class Ex5 {
    public static void main(String[] args) {
        String str1 = "kaaabcFght";
        String str2 = "ksaaabmFght";
        System.out.println(getSameLen1(str1, str2));
        System.out.println(getSameLen2(str1, str2));
    }

    public static int getSameLen1(String s1, String s2){
        int[][] dp = new int[s1.length()][s2.length()];
        char[] str1 = s1.toCharArray();
        char[] str2 = s2.toCharArray();
        int res = 0;
        for (int i = 0; i < str1.length; i++) {
            for (int j = 0; j < str2.length; j++) {
                if (i == 0 || j == 0){
                    if (str1[i] == str2[j]){
                        dp[i][j] = 1;
                        res = Math.max(dp[i][j], res);
                    }
                }else {
                    if (str1[i] == str2[j]){
                        dp[i][j] = dp[i - 1][j - 1] + 1;
                        res = Math.max(dp[i][j], res);
                    }
                }
            }
        }
        return res;
    }

    public static String  getSameLen2(String s1, String s2){
        int len = 0;
        char[] str1 = s1.toCharArray();
        char[] str2 = s2.toCharArray();
        int max = 0;
        int end = 0;
        int row = 0;
        int col = s2.length() - 1;
        while (row < s1.length()){
            len = 0;
            int i = row;
            int j = col;
            while (i < s1.length() && j < s2.length()){
                if (str1[i] == str2[j]){
                    len++;
                    if (len > max){
                        max = len;
                        end = i;
                    }
                }else {
                    len = 0;
                }
                i++;
                j++;
            }

            if (col > 0){
                col--;
            }else {
                row++;
            }
        }
        return s1.substring(end - max + 1, end + 1);
    }
}

【案例6 子序列的递归问题】

【问题描述】

 【思路解析】

因为子串一定是在字符串中满足原顺序的字符序列,可以不连续。

所以对任意dp[i][j]表示以i位置结尾的str1,表示以j位置结尾的str2的两个子串上最长公共子序列的长度。

对于这个最长公共子序列有4种可能性:

(1)最长公共子序列包含i位置,包含j位置。

(2)最长公共子序列不包含i位置,包含j位置。

(3)最长公共子序列包含i位置,不包含j位置。

(4)最长公共子序列不包含i位置,不包含j位置。

【代码实现】

package AdvancedPromotion4;

/**
 * @ProjectName: study3
 * @FileName: Ex6
 * @author:HWJ
 * @Data: 2023/9/23 22:04
 */
public class Ex6 {
    public static void main(String[] args) {
        String str1 = "kaaabcFght";
        String str2 = "ksaaabmFght";
        System.out.println(getSameLen(str1, str2));
    }

    public static int getSameLen(String s1, String s2){
        int[][] dp = new int[s1.length()][s2.length()];
        char[] str1 = s1.toCharArray();
        char[] str2 = s2.toCharArray();
        int res = 0;
        for (int i = 0; i < str1.length; i++) {
            for (int j = 0; j < str2.length; j++) {
                if (i == 0 && j == 0){
                    if (str1[i] == str2[j]){
                        dp[i][j] = 1;
                        res = dp[i][j];
                    }
                }else {
                    if (i == 0){
                        dp[i][j] = dp[i][j - 1];
                        res = Math.max(dp[i][j], res);
                    }else if(j == 0){
                        dp[i][j] = dp[i - 1][j];
                        res = Math.max(dp[i][j], res);
                    }else {
                        int p1 = dp[i][j - 1];
                        int p2 = dp[i - 1][j];
                        int p3 = dp[i - 1][j - 1] + (str1[i] == str2[j] ? 1 : 0);
                        dp[i][j] = Math.max(p1, Math.max(p2, p3));
                        res = Math.max(dp[i][j], res);
                    }

                }
            }
        }
        return res;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1035944.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Vue】ElementUI实现登录注册+axios全局配置+CORS跨域

目录 一、搭建项目 1.1 安装 Element-UI 1.2 导入组件 1.3 创建登录、注册界面 二、后台交互 2.1 引入axios 2.2 添加vue-axios的全局配置 2.2 ssm项目准备 (后端) 2.2.1 准备数据表 2.2.2 导入ssm项目 2.2.3 编写控制器 2.3 前端编写 2.4 登入测试 2.5 注册测试…

亚马逊云科技携手西门子运用生成式AI之力,打破数据孤岛

2023年&#xff0c;以基于GPT模型对话应用为代表的生成式AI浪潮席卷全球&#xff0c;引起企业广泛关注。自此&#xff0c;由生成式AI引导的企业变革序幕全面展开&#xff0c;企业向数智化转型迈出了坚实的一步。 西门子股份公司&#xff08;以下简称“西门子”&#xff09;是一…

《C++ primer》练习6.54-6.56:函数指针定义并调用

《C primer》里面讲到函数指针定义并调用&#xff0c;做一下练习6.54-6.56&#xff0c;题目如下&#xff1a; vector元素的类型是函数指针的类型是int (*)(int, int)&#xff0c;指向的元素是有两个int形参&#xff0c;返回类型也是int的函数。 #include <vector> #incl…

如何利用人才测评系统提升企业招聘效率

公司需要的是能产出价值的员工&#xff0c;但是要想找到完全符合条件的员工&#xff0c;其实并不容易&#xff0c;尽管应聘的人数很多&#xff0c;但不是跳槽的&#xff0c;就是转行的&#xff0c;要么就只能从应届生培养开始了。 从招聘流程上&#xff0c;以现在的模式&…

使用 PyTorch 的计算机视觉简介 (6/6)

一、说明 本文主要介绍CNN中在pytorch的实现&#xff0c;其中MobileNet 网络&#xff0c;数据集来源&#xff0c;以及训练过程&#xff0c;模型生成和存储&#xff0c;模型调入等。 二、轻量级网络和移动网络 我们已经看到&#xff0c;复杂的网络需要大量的计算资源&#xff0c…

4位密码锁可修改密码及错误报警VHDL

名称&#xff1a;4位密码锁可修改密码及错误报警&#xff08;代码在文末付费下载&#xff09; 软件&#xff1a;Quartus 语言&#xff1a;VHDL 要求&#xff1a; 按键包括&#xff0c;0~9&#xff0c;确认&#xff0c;重置&#xff0c;修改,密码4位 要能设定密码&#xff0c…

【PowerQuery】Python自动刷新本地数据

Python数据刷新是开发爱好者和开发人员开发的PowerBI刷新模块进行数据刷新的手段,Python进行数据刷新是通过刷新PowerBI Desktop 的模式进行数据刷新。目前常用的Python的数据刷新模块是PbixRefresher,图为相关的模块和版本。 由于当前的脚本基于英文版本的PowerBI Desktop进…

罗德里格斯公式

1.点乘 A ⃗ ⋅ B ⃗ ∣ A ⃗ ∣ ∣ B ⃗ ∣ c o s ⟨ A ⃗ , B ⃗ ⟩ \vec{A} \cdot \vec{B} \left | \vec{A} \right | \left | \vec{B} \right | cos\left \langle \vec{A}, \vec{B} \right \rangle A ⋅B ​A ​ ​B ​cos⟨A ,B ⟩ 对应几何意义&#xff1a;向量 A ⃗…

驱动代码整理

一&#xff0c;控制LED灯控制实验 头文件 #ifndef __HEAD_H__ #define __HEAD_H__#define LED1_MODER 0X50006000 #define LED1_ODR 0X50006014 #define LED1_RCC 0X50000A28#endif 驱动 #include <linux/init.h> #include <linux/module.h> #include &l…

Vue模板语法【下】事件处理器,表单、自定义组件、通信组件

目录 一、事件处理器 1.1常用的事件修饰符 1.2常用的按键修饰符 二&#xff0c;vue中的表单 三、自定义组件 四&#xff0c;通信组件 一、事件处理器 1.1常用的事件修饰符 Vue的事件修饰符是用来改变事件的默认行为或者添加额外的功能。以下是一些常用的事件修饰符及其…

Github 上很火的开源网页图标

Devicon https://devicon.dev 一系列关于编程语言、设计和开发工具的图标&#xff0c;提供了字体格式和 SVG 代码可以直接应用在你的项目中 VSCode Icons https://github.com/microsoft/vscode-icons#readme 收藏了 Visual Studio Code 软件上的所有的图标 Weather Icons https…

【06】FISCOBCOS中的节点前置服务

WeBASE管理平台 微众银行开源的自研区块链中间件平台——WeBASE(WeBank Blockchain Application Software Extension) 是区块链应用和FISCO BCOS节点之间搭建的中间件平台。WeBASE屏蔽了区块链底层的复杂度,降低区块链使用的门槛,大幅提高区块链应用的开发效率,包含节点前置…

【深度学习】图像去噪(2)——常见网络学习

【深度学习】图像去噪 是在 【深度学习】计算机视觉 系列文章的基础上&#xff0c;再次针对深度学习&#xff08;尤其是图像去噪方面&#xff09;的基础知识有更深入学习和巩固。 1 DnCNN 1.1 网络结构 1.1.1 残差学习 1.1.2 Batch Normalization (BN) 1.1.2.1 背景和目标…

手机也可以将声音转为字幕!支持中英日韩4种语言

快去看看你的华为手机有没有这个功能——AI字幕&#xff0c;可以将手机里的音频转换为文字&#xff08;以字幕形式展现&#xff0c;可保存在手机备忘录&#xff09; AI字幕有什么用途&#xff1f; 1. 在听觉不太好使的环境下&#xff0c;将音频信息转化到视觉&#xff08;文本…

OpenGLES:单纹理贴图

一.概述 最近疏于写博客&#xff0c;接下来会陆续更新这段时间OpenGLES的一些开发过程。 前两篇OpenGLES的博客讲解了怎样使用OpenGLES实现相机普通预览和多宫格滤镜 在相机实现过程中&#xff0c;虽然使用到了纹理&#xff0c;但只是在生成一个纹理之后&#xff0c;使用纹理…

基于SpringBoot+Vue+支付宝支付的汽车租赁系统(可做毕设/课设)

技术栈 前后端分离 前端使用: Vue Element 后端使用: SpringBoot Mysql8.0 Mybatis 支付宝支付 功能 分为 管理员端 和 普通用户端 和 维修人员端 普通用户端 1.首页 展示所有品牌,汽车,公告,按关键字搜索汽车名 2.汽车详情页 展示汽车详情和评价 3.下单支付和退押金 立即下单…

vue3 - 开发和生产环境通过Mock模拟真实接口请求

GitHub Demo 地址 在线预览 在前端开发中&#xff0c;常常需要与后端接口进行交互。然而&#xff0c;在接口尚未实现或者正在开发的情况下&#xff0c;前端开发人员往往无法得到真实的接口数据&#xff0c;这给开发和测试工作带来了一定的困扰。对此&#xff0c;可以通过Mock模…

《动手学深度学习 Pytorch版》 7.7 稠密连接网络

7.7.1 从 ResNet 到 DenseNet DenseNet 可以视为 ResNet 的逻辑扩展。 ResNet 将函数展开为 f ( x ) x g ( x ) f(\boldsymbol{x})xg(\boldsymbol{x}) f(x)xg(x)&#xff0c;即一个简单的线性项和一个复杂的非线性项。 若将 f f f 拓展成超过两部分&#xff0c;则 Dense…

CRM客户管理系统英文专业版

外资公司日常沟通的语言以英文为主&#xff0c;业务往来也是涉及到国内外&#xff0c;专业的英文版CRM系统很适合这样的业务团队&#xff0c;尤其CRM供应商是国际化企业&#xff0c;在海外也有分公司、办事处。 多语言 ZOHO支持多语种如英语、汉语、日语等28种语言&#xff0…

Next.js 13.5 正式发布,速度大幅提升!

9 月 19 日&#xff0c;Next.js 13.5 正式发布&#xff0c;该版本通过以下方式提高了本地开发性能和可靠性&#xff1a; 本地服务器启动速度提高 22%&#xff1a;使用App和Pages Router可以更快地进行迭代 HMR&#xff08;快速刷新&#xff09;速度提高 29%&#xff1a;在保存…