算法拾遗二十五之暴力递归到动态规划五

news2024/11/15 11:29:14

算法拾遗二十七之暴力递归到动态规划七

      • 题目一【数组累加和最小的】
      • 题目二
        • 什么暴力递归可以继续优化
        • 暴力递归和动态规划的关系
        • 面试题和动态规划的关系
        • 如何找到某个问题的动态规划方式
        • 面试中设计暴力递归的原则
        • 知道了暴力递归的原则 然后设计
        • 常见的四种尝试模型
        • 如何分析有没有重复解
        • 暴力递归到动态规划的套路
        • 动态规划的进一步优化
      • N皇后问题

题目一【数组累加和最小的】

在这里插入图片描述
找较小的集合最接近两个集合总和的一半:

	public static int right(int[] arr) {
		if (arr == null || arr.length < 2) {
			return 0;
		}
		//统计所有数的累加和
		int sum = 0;
		for (int num : arr) {
			sum += num;
		}
		return process(arr, 0, sum / 2);
	}

	// arr[i...]从i位置出发及其后面的数可以自由选择,
	// 请返回累加和尽量接近rest,但不能超过rest的情况下,最接近的累加和是多少?
	public static int process(int[] arr, int i, int rest) {
		if (i == arr.length) {
			return 0;
		} else { // 还有数,arr[i]这个数
			// 可能性1,不使用arr[i],直接index+1,rest不变
			int p1 = process(arr, i + 1, rest);
			// 可能性2,要使用arr[i]
			int p2 = 0;
			if (arr[i] <= rest) {
				p2 = arr[i] + process(arr, i + 1, rest - arr[i]);
			}
			return Math.max(p1, p2);
		}
	}

改dp,有两个可变参数:
i变化范围为0-N,rest变化范围,从0-sum/2,不会超过此范围。
先看basecase:
在这里插入图片描述
分析普遍位置依赖关系:
i位置依赖于i+1位置
在这里插入图片描述

   public static int dp1(int[] arr) {
        if (arr == null || arr.length < 2) {
            return 0;
        }
        int sum = 0;
        for (int num : arr) {
            sum += num;
        }
        sum /= 2;
        int N = arr.length;
        int[][] dp = new int[N + 1][sum + 1];
        /*
         int p1 = process(arr, i + 1, rest);
            // 可能性2,要使用arr[i]
            int p2 = 0;
            if (arr[i] <= rest) {
                p2 = arr[i] + process(arr, i + 1, rest - arr[i]);
            }
         */
        for (int i = N - 1; i >= 0; i--) {

            for (int rest = 0; rest <= sum; rest++) {

                int p1 = dp[i + 1][rest];
                int p2 = 0;
                if (arr[i] <= rest) {
                    p2 = arr[i] + dp[i + 1][rest - arr[i]];
                }
                dp[i][rest] = Math.max(p1, p2);
            }
        }
        return dp[0][sum];
    }

    public static int[] randomArray(int len, int value) {
        int[] arr = new int[len];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int) (Math.random() * value);
        }
        return arr;
    }

    public static void printArray(int[] arr) {
        for (int num : arr) {
            System.out.print(num + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        int maxLen = 20;
        int maxValue = 50;
        int testTime = 10000;
        System.out.println("测试开始");
        for (int i = 0; i < testTime; i++) {
            int len = (int) (Math.random() * maxLen);
            int[] arr = randomArray(len, maxValue);
            int ans1 = right(arr);
            int ans2 = dp1(arr);
            if (ans1 != ans2) {
                printArray(arr);
                System.out.println(ans1);
                System.out.println(ans2);
                System.out.println("Oops!");
                break;
            }
        }
        System.out.println("测试结束");
    }

题目二

在这里插入图片描述

 public static int right1(int[] arr) {
        if (arr == null || arr.length < 2) {
            return 0;
        }
        int sum = 0;
        for (int num : arr) {
            sum += num;
        }

        if ((arr.length & 1) == 0) {
            return process1(arr, 0, arr.length / 2, sum / 2);
        } else {
            return Math.max(process1(arr, 0, arr.length / 2, sum / 2), process1(arr, 0, arr.length / 2 + 1, sum / 2));
        }
    }


    public static int process1(int[] arr, int i, int picks, int rest) {
        if (i == arr.length) {
            //没有数的情况,没法调返回一个-1表示这个过程不能使用
            return picks == 0 ? 0 : -1;
        } else {
            //还有数挑
            //第一种选择不挑当前数
            int p1 = process1(arr, i + 1, picks, rest);
            int p2 = -1;
            int next = -1;
            if (arr[i] <= rest) {
                next = process1(arr, i + 1, picks - 1, rest - arr[i]);
            }
            if (next != -1) {
                //如果后续是有效的才有可能性2
                p2 = arr[i] + next;
            }

            return Math.max(p1,p2);
        }
    }

改dp:三个可变参数可用一个三维dp解决

在这里插入图片描述

  public static int dp4(int[] arr) {
        if (arr == null || arr.length < 2) {
            return 0;
        }
        int sum = 0;
        for (int num : arr) {
            sum += num;
        }
        sum /= 2;
        int N = arr.length;
        int M = (N + 1) / 2;
        int[][][] dp = new int[N + 1][M + 1][sum + 1];

        for (int i = 0; i <= N; i++) {
            for (int j = 0; j <= M; j++) {
                for (int k = 0; k <= sum; k++) {
                    dp[i][j][k] = -1;
                }
            }
        }

    /*    if (i == arr.length) {
            //没有数的情况,没法调返回一个-1表示这个过程不能使用
            return picks == 0 ? 0 : -1;
        }*/
        for (int rest = 0; rest <= sum; rest++) {
            dp[N][0][rest] = 0;
        }

        for (int i = N - 1; i >= 0; i--) {
            for (int picks = 0; picks <= M; picks++) {
                for (int rest = 0; rest <= sum; rest++) {
              /*      //还有数挑
                    //第一种选择不挑当前数
                    int p1 = process1(arr, i + 1, picks, rest);
                    int p2 = -1;
                    int next = -1;
                    if (arr[i] <= rest) {
                        next = process1(arr, i + 1, picks - 1, rest - arr[i]);
                    }
                    if (next != -1) {
                        //如果后续是有效的才有可能性2
                        p2 = arr[i] + next;
                    }

                    return Math.max(p1, p2);*/
                    int p1 = dp[i + 1][picks][rest];
                    int p2 = -1;
                    int next = -1;
                    if (picks - 1 >= 0 && arr[i] <= rest) {
                        next = dp[i + 1][picks - 1][rest - arr[i]];
                    }
                    if (next != -1) {
                        p2 = arr[i] + next;
                    }

                    dp[i][picks][rest] = Math.max(p1,p2);
                }
            }
        }

        if ((arr.length & 1) == 0) {
            return dp[0][arr.length / 2][sum];
        } else {
            return Math.max(dp[0][arr.length / 2][sum], dp[0][(arr.length / 2) + 1][sum]);
        }
    }

什么暴力递归可以继续优化

在这里插入图片描述
在这里插入图片描述

暴力递归和动态规划的关系

在这里插入图片描述

面试题和动态规划的关系

在这里插入图片描述

如何找到某个问题的动态规划方式

在这里插入图片描述

面试中设计暴力递归的原则

在这里插入图片描述

知道了暴力递归的原则 然后设计

在这里插入图片描述

常见的四种尝试模型

在这里插入图片描述

如何分析有没有重复解

在这里插入图片描述

暴力递归到动态规划的套路

在这里插入图片描述

动态规划的进一步优化

在这里插入图片描述

N皇后问题

在这里插入图片描述
在这里插入图片描述
如上算是一种解,考虑皇后的时候一行一行的填入皇后,每一行填入一个皇后,这样就不用检查两个皇后是否共行了。
之前的某个皇后在(x,y),然后当前位置在(甲,乙)位置
如果y==乙或者甲减去x的绝对值等于y-乙的绝对值【共斜线】
复杂度为O(n的n次方)
每一行都有n种决策

public static int num1(int n) {
		if (n < 1) {
			return 0;
		}
		int[] record = new int[n];
		return process1(0, record, n);
	}

	// 当前来到i行,一共是0~N-1行
	// 在i行上放皇后,所有列都尝试
	// 必须要保证跟之前所有的皇后不打架
	// int[] record record[x] = y 之前的第x行的皇后,放在了y列上,一维数组的列号表示n皇后的行号
	// 返回:不关心i以上发生了什么,i.... 后续有多少合法的方法数
	public static int process1(int i, int[] record, int n) {
		//i来到n位置未发生打架
		if (i == n) {
			return 1;
		}
		int res = 0;
		// i行的皇后,放哪一列呢?j列,
		for (int j = 0; j < n; j++) {
			if (isValid(record, i, j)) {
				record[i] = j;
				res += process1(i + 1, record, n);
			}
		}
		return res;
	}

	/**
	 * 判断是否发生打架
	 *
	 * @param record
	 * @param i
	 * @param j
	 * @return
	 */
	public static boolean isValid(int[] record, int i, int j) {
		// 0..i-1,检查0->i-1行的皇后是否发生打架
		for (int k = 0; k < i; k++) {
			if (j == record[k] || Math.abs(record[k] - j) == Math.abs(i - k)) {
				return false;
			}
		}
		return true;
	}

位运算优化常数时间:
在这里插入图片描述
能选的位置是列或上左下与右下还是0的位置。
同理再定义一个第0行的x位置是皇后放置的位置,或出来三个方框的位置是第一行不能选的。
在这里插入图片描述
每次放一个皇后都要更新列限制,左下限制以及右下限制。
假设某个时刻是这样的:
在这里插入图片描述
最后是1的不能放皇后是0的可以,然后整体取反变成其他的全1中间的三个1变成三个0
limit是0…011111110…0,然后与一下得到limit=1100011,其中1是能放n皇后的位置

// 请不要超过32皇后问题
	public static int num2(int n) {
		if (n < 1 || n > 32) {
			return 0;
		}
		// 如果你是13皇后问题,limit 最右13个1,其他都是0,通过整数的位来标记皇后
		int limit = n == 32 ? -1 : (1 << n) - 1;
		return process2(limit, 0, 0, 0);
	}

	// 7皇后问题
	// limit : 0....0 1 1 1 1 1 1 1
	// 之前皇后的列影响:colLim
	// 之前皇后的左下对角线影响:leftDiaLim
	// 之前皇后的右下对角线影响:rightDiaLim
	public static int process2(int limit, int colLim, int leftDiaLim, int rightDiaLim) {
		//列影响等于了limit
		if (colLim == limit) {
			return 1;
		}
		// pos中所有是1的位置,是你可以去尝试皇后的位置
		int pos = limit & (~(colLim | leftDiaLim | rightDiaLim));
		int mostRightOne = 0;
		int res = 0;
		while (pos != 0) {
			mostRightOne = pos & (~pos + 1);
			pos = pos - mostRightOne;
			res += process2(limit, colLim | mostRightOne, (leftDiaLim | mostRightOne) << 1,
					(rightDiaLim | mostRightOne) >>> 1);//无符号右移
		}
		return res;
	}

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

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

相关文章

力扣-丢失信息的雇员

大家好&#xff0c;我是空空star&#xff0c;本篇带大家了解一道简单的力扣sql练习题。 文章目录前言一、题目&#xff1a;1965. 丢失信息的雇员二、解题1.正确示范①提交SQL运行结果2.正确示范②提交SQL运行结果3.正确示范③提交SQL运行结果4.正确示范④提交SQL运行结果5.其他…

SpringBoot高级-Condition相关操作

01-SpringBoot高级-今日内容 SpringBoot自定配置SpringBoot事件监听SpringBoot流程分析SpringBoot监控SpringBoot部署 02-SpringBoot自动配置-Condition-1 Condition是Spring4.0后引入的条件化配置接口&#xff0c;通过实现Condition接口可以完成有条件的加载相应的Bean Co…

移动架构43_什么是Jetpack

Android移动架构汇总​​​​​​​ 文章目录一 Android 开发框架演变1 MVC2 MVP3 MVVM二 什么是JetPack三 如何构建支持Jetpack项目一 Android 开发框架演变 1 MVC Model-View-Controller&#xff0c;模型-视图-控制器&#xff0c;Model负责数据管理&#xff0c;View负责UI显…

创建Vite+Vue3+TS基础项目

前言&#xff1a; 本篇内容不涉及插件的安装以及配置&#xff0c;具体安装及配置篇可以看下面目录&#xff0c;本篇只涉及创建ViteVue3TS基础项目相关内容。不讲废话&#xff0c;简单直接直接开撸。 目录 npm create vite vue3练习2 -- --template vue-ts npm i vue-rout…

线性表 顺序表数组

初识线性表 文章目录初识线性表线性表的类型定义基本操作&#xff08;一&#xff09;init&#xff0c;destory&#xff0c;clear基本操作&#xff08;二&#xff09; 判空 &#xff0c;求长基本操作&#xff08;三&#xff09;取值&#xff0c;取位置基本操作&#xff08;四&am…

图解LeetCode——剑指 Offer 12. 矩阵中的路径

一、题目 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 单词必须按照字母顺序&#xff0c;通过相邻的单元格内的字母构成&#xff0c;其中“相邻”单元格是那些水平相…

Solon2 的应用生命周期

Solon 框架的应用生命周期包括&#xff1a;一个初始化函数时机点 六个事件时机点 两个插件生命时机点 两个容器生命时机点&#xff08;v2.2.0 版本的状态&#xff09;&#xff1a; 提醒&#xff1a; 启动过程完成后&#xff0c;项目才能正常运行&#xff08;启动过程中&…

基于麻雀算法改进的BP神经网络客流量预测,SSA-BP

目录 背影 BP神经网络的原理 BP神经网络的定义 BP神经网络的基本结构 BP神经网络的神经元 BP神经网络的激活函数&#xff0c; BP神经网络的传递函数 麻雀算法原理 麻雀算法主要参数 麻雀算法流程图 麻雀算法优化测试函数代码 基于麻雀算法改进的BP神经网络坑基监测 数据 matlab…

Windows 11 安装 Docker Desktop

Windows 环境安装 WSL2 WSL 简介 WSL 全称是 Windows Subsystem for Linux &#xff0c;适用于 Linux 的 Windows 子系统&#xff0c;可让开发人员按原样运行 GNU/Linux 环境&#xff0c;包括大多数命令行工具、实用工具和应用程序&#xff0c;且不会产生传统虚拟机或双启动设…

低线城市外卖市场逐渐下沉,创业者如何有效开展本地外卖平台

近年来&#xff0c;我国网上外卖营业额不断上升&#xff0c;使我国餐饮业的比重越来越高。 随着外卖市场的下沉&#xff0c;低线城市的用户开始使用外卖平台 由于我国在线外卖行业逐渐成熟&#xff0c;一、二线主流市场逐渐饱和&#xff0c;外卖行业逐渐开始向低线城市发展&…

非标自动化设备远程监控解决方案

为了实现企业自动化生产&#xff0c;提高工作效率和稳定性&#xff0c;需对整个工厂进行远程监控和管理。 在工厂建立了一个远程监控系统&#xff0c;可以实现对工业自动化的设备状态进行远程实时监控&#xff0c;同时可以利用无线网络技术来实现对设备的数据采集和远程管理。 …

Guava ——Joiner和Splitter

大家好&#xff0c;这里是一口八宝周&#x1f44f;欢迎来到我的博客❤️一起交流学习 文章中有需要改进的地方请大佬们多多指点 谢谢&#x1f64f;在本篇文章中&#xff0c;我将用实例展示&#xff0c;如何使用Joiner将集合转换为 String &#xff0c;以及使用Splitter将 Strin…

如何使用EvilTree在文件中搜索正则或关键字匹配的内容

关于EvilTree EvilTree是一款功能强大的文件内容搜索工具&#xff0c;该工具基于经典的“tree”命令实现其功能&#xff0c;本质上来说它就是“tree”命令的一个独立Python 3重制版。但EvilTree还增加了在文件中搜索用户提供的关键字或正则表达式的额外功能&#xff0c;而且还…

Android性能优化系列篇:弱网优化

弱网优化1、Serializable原理通常我们使用Java的序列化与反序列化时&#xff0c;只需要将类实现Serializable接口即可&#xff0c;剩下的事情就交给了jdk。今天我们就来探究一下&#xff0c;Java序列化是怎么实现的&#xff0c;然后探讨一下几个常见的集合类&#xff0c;他们是…

sklearn中的数据预处理和特征工程

目录 一.数据挖掘的五大流程 1. 获取数据 2. 数据预处理 3. 特征工程&#xff1a; 4. 建模&#xff0c;测试模型并预测出结果 5. 上线&#xff0c;验证模型效果 二.数据预处理 1.数据无量纲化 2.preprocessing.MinMaxScaler(数据归一化) 3.preprocessing.Standard…

Linux编译器——gcc/g++(预处理、编译、汇编、链接)

目录 0.程序实现的两大环境 1.gcc如何完成 预处理 编译 汇编 链接 2.动态库与静态库 对比二者生成的文件大小 3. gcc常用选项 0.程序实现的两大环境 任何一个C程序的实现都要经过翻译环境与执行环境。 在翻译环境中又分为4个部分&#xff0c;预编译、编译、汇编与链…

Spring Cloud配置application.yml与bootstrap.yml区别及多profile配置 | Spring Cloud 6

一、前言 Spring Cloud 构建于 Spring Boot 之上&#xff0c;在 Spring Boot 中有两种上下文&#xff0c;一种是 bootstrap&#xff0c;另外一种是 application。 二、bootstrap与application (.yml/.properties) 2.1 两者区别 bootstrap.yml/bootstrap.properties 和 appl…

CHAPTER 3 Web HA集群部署 - Keepalived

Web HA集群部署 - Keepalived1. Keepalived概述1.1 工作原理1.2 核心功能1.3 拓扑图2. KeepAlived安装方式2.1 yum源安装2.2 源码包编译3. KeepAlived安装3.1 环境依赖3.2 安装nginx3.3 安装Keepalived4. Keepalived部署4.1 主备模式1. 节点配置2. 主节点配置文件3. 从节点配置…

金三银四了,准备跳槽的可以看看....

前两天跟朋友感慨&#xff0c;去年的铜九铁十、裁员、疫情导致好多人都没拿到offer!现在已经3月了&#xff0c;具体的金三银四也已经到来了。 对于想跳槽的职场人来说&#xff0c;绝对要已经提前做准备了。这时候&#xff0c;很多高薪技术岗、管理岗的缺口和市场需求也出来了。…

谷粒学苑第七 八 九天

谷粒学苑第七天 上传到服务器 文件上传到接口中 在接口中读取内容 加到数据库 swagger&#xff1a; 报了实体类的错&#xff1a;刚刚这里忘记写数据了 一级二级都查出来了&#xff1a; 课程发布流程确认 报错&#xff1a; 实体类全部改为_STR还是报错 org.springfr…