根据数据规模猜解法

news2024/12/25 13:52:49

文章目录

  • 0、结论
  • 1、题目
    • 1.1 题目描述
    • 1.2 思路分析
      • 1.2.1 暴力递归解法1
      • 1.2.2 解法1修改成动态规划
      • 1.2.3 暴力递归解法2
      • 1.2.4 解法2修改成动态规划
      • 1.2.5 对数器
    • 1.3 小结
  • 2、总结

0、结论

1)C/C++,1秒处理的指令条数为 1 0 8 10^8 108

2)Java等语言,2~4秒处理的指令条数为 1 0 8 10^8 108

说明:基于上述结论,假设题目给定的数组长度为 1 0 6 10^6 106,如果写出来的算法时间复杂度是 O ( N 2 ) O(N^2) O(N2),那么在规定的时间内一定是不能通过的,至少需要一个 O ( N l o g N ) O(NlogN) O(NlogN) 的算法,甚至可以优化到 O ( N ) O(N) O(N)。 若给定的数组长度为 1 0 3 10^3 103,则可知道 O ( N 2 ) O(N^2) O(N2)复杂度的解法足够可以拿下该题,不用再花时间进行优化了。

所以可以通过数据量反推出需要一个什么样的解法。

1、题目

1.1 题目描述

给定数组 int[] d,其中 d[i] 表示 i 号怪兽的能力;

给定数组 int[] p,其中 p[i] 表示贿赂 i 号怪兽需要的钱。

开始时你的能力是 0,你的目标是从 0 号怪兽开始,通过所有的怪兽。

如果你当前的能力,小于 i 号怪兽的能力,你必须付出 p[i] 的钱,贿赂这个怪兽,然后怪兽就会加入你,他的能力直接累加到你的能力上;如果你当前的能力,大于等于 i 号怪兽的能力,你可以选择直接通过,你的能力并不会下降,你也可以选择贿赂这个怪兽,然后怪兽就会加入你,他的能力直接累加到你的能力上。

返回通过所有的怪兽,需要花的最小钱数。

1.2 思路分析

根据不同数据规模,有不同的解法。

本题是个简单的动态规划问题。

1.2.1 暴力递归解法1

第一种尝试方法:
在这里插入图片描述
dp[i][j] (即表中格子表示的意义)表示从第 0 号通关到第 i i i 号怪兽,能力值 ≥ j \ge j j时,最少使用的钱数;如果能力值无法达到 j j j,则为-1。

d p [ i ] [ j ] = { d p [ i + 1 ] [ j + d [ i ] ] + p [ i ]   j < d [ i ] ,只能贿赂  m i n { d p [ i + 1 ] [ j + d [ i ] ] + p [ i ]  贿赂 i 号怪兽  d p [ i + 1 ] [ j ]  不贿赂 i 号怪兽    j ≥ d [ i ] ,可以选择 dp[i][j] = \begin{cases} dp[i+1][j + d[i]] + p[i] &\text{ $j < d[i]$,只能贿赂 }\\ min \begin{cases} dp[i+1][j + d[i]] + p[i] &\text{ 贿赂$i$号怪兽 }\\ dp[i+1][j] &\text{ 不贿赂$i$号怪兽 } \end{cases}&\text{ $j \ge d[i]$,可以选择}\\ \end{cases} dp[i][j]= dp[i+1][j+d[i]]+p[i]min{dp[i+1][j+d[i]]+p[i]dp[i+1][j] 贿赂i号怪兽  不贿赂i号怪兽  j<d[i],只能贿赂  jd[i],可以选择

public class MoneyProblem {
	// int[] d d[i]:i号怪兽的武力
	// int[] p p[i]:i号怪兽要求的钱
	// ability 当前你所具有的能力
	// index 来到了第index个怪兽的面前

	// 目前,你的能力是ability,你来到了index号怪兽的面前,如果要通过后续所有的怪兽,请返回需要花的最少钱数
	public static long process1(int[] d, int[] p, int ability, int index) {
		if (index == d.length) {
			return 0;
		}
		if (ability < d[index]) { //只能贿赂
			return p[index] + process1(d, p, ability + d[index], index + 1);//当前花费的 + 后续至少要花费的
		} else { // ability >= d[index] 可以贿赂,也可以不贿赂
			return Math.min(p[index] + process1(d, p, ability + d[index], index + 1) /*贿赂*/,
							0 + process1(d, p, ability, index + 1) /*不贿赂*/);
		}
	}

	public static long func1(int[] d, int[] p) {
		return process1(d, p, 0, 0);
	}
}

弊端:递归函数 long process1(int[] d, int[] p, int ability, int index),两个可变参数(能力ability 和 怪兽的个数index),改成动态规划要借助这两个参数。但是当怪兽的能力值特别大时,如1亿、4亿等,且最大能力是所有能力值的累加和,即使改成动态规划,也是无法在 1 0 8 10^8 108 条指令内执行完毕的。

1.2.2 解法1修改成动态规划

public static class MoneyProblem {
	public static long minMoney1(int[] d, int[] p) {
		int sum = 0;
		for (int num : d) {
			sum += num;
		}
		long[][] dp = new long[d.length + 1][sum + 1];
		for (int i = 0; i <= sum; i++) {
			dp[0][i] = 0;
		}
		for (int cur = d.length - 1; cur >= 0; cur--) {
			for (int hp = 0; hp <= sum; hp++) {
				// 如果这种情况发生,那么这个hp必然是递归过程中不会出现的状态
				// 既然动态规划是尝试过程的优化,尝试过程碰不到的状态,不必计算
				if (hp + d[cur] > sum) {
					continue;
				}
				if (hp < d[cur]) {
					dp[cur][hp] = p[cur] + dp[cur + 1][hp + d[cur]];
				} else {
					dp[cur][hp] = Math.min(p[cur] + dp[cur + 1][hp + d[cur]], dp[cur + 1][hp]);
				}
			}
		}
		return dp[0][0];
	}
}

1.2.3 暴力递归解法2

第二种尝试方法:
在这里插入图片描述
定义 dp[i][j] (即表中格子表示的意义)表示从第 0 号通关到第 i i i 号怪兽,严格花费 j j j 元能达到的最大能力;如果没法正好使用 j j j 元 或者 使用了 j j j 元,但是无法到达 i i i 号怪兽,均为-1。如果能将整张表顺利填写完毕,那么第 N − 1 N-1 N1 行从左往右遍历哪个值不是-1,它对应的钱数就是答案。

分析转移条件

两种选择:

① 方案1:不贿赂 i i i 号怪兽。

此时的 dp[i][j] 就是说从 0 通关到 i − 1 i-1 i1 号怪兽,严格花了 j j j 元,即 dp[i-1][j]

但是如果 dp[i-1][j] = -1,表示从 0 通关到 i − 1 i-1 i1,只花 j j j 元的情况下,没有可以通关的方案。此时不能选择第 1 种方案,因为在不贿赂 i i i 号的情况下,还想维持 j j j 元的前提是严格花费 j j j 元,能通过前面的 0 ~ i − 1 i-1 i1 号怪兽,而现在花费了 j j j 元,前面的 i − 1 i-1 i1 个怪兽都通过不了,所以无法做这种选择。

所以方案1——“不贿赂 i i i 号怪兽” 成立的第一个条件是 dp[i-1][j] ≠ -1

其次,第二个条件,当通过 0 到 i − 1 i-1 i1 号怪兽获得的能力大于等于第 i i i 号怪兽的能力,即 dp[i-1][j] ≥ d[i] 时,才不用贿赂。

当两个条件都成立时,dp[i][j] = dp[i-1][j]

②方案2:贿赂 i i i 号怪兽

假设 i i i 号怪兽的能力是 x x x,贿赂它需要的金额是 y y y 元。

选择贿赂 i i i 号怪兽,且整体要凑出 j j j 元,那么严格使用 j − y j-y jy 元时,能通过 0 号到 i − 1 i-1 i1 号怪兽,否则,是到不了 i i i 号怪兽这里来做选择的。而已经决定贿赂了,所以能力值不重要了。

所以方案2——“选择贿赂 i i i 号怪兽”成立的条件是 dp[i-1][j-y] ≠ -1

整理两种选择方案可得:

d p [ i ] [ j ] = m a x { d p [ i − 1 ] [ j ]   d p [ i − 1 ] [ j ] ≠ − 1  且  d p [ i − 1 ] [ j ] ≥ d [ i ]   d p [ i − 1 ] [ j − p [ i ] ] + d [ i ]   d p [ i − 1 ] [ j − p [ i ] ] ≠ − 1 dp[i][j] = max\begin{cases} dp[i-1][j] &\text{ $dp[i-1][j] \ne -1$ 且 $dp[i-1][j] \ge d[i]$ }\\ dp[i-1][j - p[i]] + d[i] &\text{ $dp[i-1][j-p[i]] \ne -1$}\\ \end{cases} dp[i][j]=max{dp[i1][j]dp[i1][jp[i]]+d[i] dp[i1][j]= dp[i1][j]d[i]  dp[i1][jp[i]]=1

public class MoneyProblem {
	//从第0号到第index号怪兽,花费的钱必须严格等于money
	//如果通过不了,返回-1
	//如果可以通过,返回能通过情况下的最大能力值
	public static long process2(int[] d, int[] p, int index, int money) {
		if (index == -1) { //一个怪兽也没遇到,只能花费0元
			return money == 0 ? 0 : -1; //如果money不等于0,意思就是必须要在没遇到怪兽的时候花费money>0,没有这种方案
		}
		
		//index >= 0
		//1)不贿赂当前index号怪兽
		long preMaxAbility = process2(d, p, index - 1, money); //不贿赂index号怪兽时,之前的那些怪兽是否能通过,如果能通过获得的能力值
		long p1 = -1;
		if (preMaxAbility != -1 && preMaxAbility >= d[index]) { //之前的怪兽能通过 且 获得的能力大于当前怪兽的能力时才不需要贿赂
			p1 = preMaxAbility; //如果if中的条件不成立,所以就没有不贿赂当前index号怪兽这种方案存在,p1维持为-1
		}
		
		//2) 贿赂当前index号怪兽
		//则之前通过0到index-1号要正好花掉money-p[index]元,才能在贿赂index号的时候,一共凑够money元
		long preMaxAbility2 = process2(d, p, index - 1, money - p[index]); 
		long p2 = -1;
		if (preMaxAbility2 != -1) {
			p2 = d[index] + preMaxAbility2; //贿赂后获得当前怪兽的能力
		}
		
		return Math.max{p1, p2}; //返回最大能力值
	} 
	
	public static int func2(int[] d, int[] p) {
		int allMoney = 0;
		//所有怪兽要花的钱累加,就是要花费的钱的极限
		for (int i = 0; i < p.length; i++) {
			allMoney += p[i];
		}
		
		int n = d.length;
		// 从0元钱开始尝试
		for (money = 0; money < allMoney; money++) {
			if (process2(d, p, n-1, money) != -1) { //如果返回的最大能力值不等于-1,就找到了通过所有怪兽,花费最少的钱
				return money;
			}
		}
		
		return allMoney; //如果在上面的尝试中都没有找到方案,那就只能花费所有的钱去贿赂所有的怪兽这种方案
	} 
}

弊端:递归函数long process2(int[] d, int[] p, int index, int money),两个可变参数(怪兽的个数index 和 贿赂怪兽的钱money),改成动态规划要借助这两个参数,但是当贿赂怪兽的钱的值范围特别大的时候,即使改成动态规划,在 1 0 8 10^8 108 内也无法填完整张表。

1.2.4 解法2修改成动态规划

public class MoneyProblem {
	public static long minMoney2(int[] d, int[] p) {
		int sum = 0;
		for (int num : p) {
			sum += num;
		}
		// dp[i][j]含义:
		// 能经过0~i的怪兽,且花钱为j(花钱的严格等于j)时的武力值最大是多少?
		// 如果dp[i][j]==-1,表示经过0~i的怪兽,花钱为j是无法通过的,或者之前的钱怎么组合也得不到正好为j的钱数
		int[][] dp = new int[d.length][sum + 1];
		for (int i = 0; i < dp.length; i++) {
			for (int j = 0; j <= sum; j++) {
				dp[i][j] = -1;
			}
		}
		// 经过0~i的怪兽,花钱数一定为p[0],达到武力值d[0]的地步。其他第0行的状态一律是无效的
		dp[0][p[0]] = d[0];
		for (int i = 1; i < d.length; i++) {
			for (int j = 0; j <= sum; j++) {
				// 可能性一,为当前怪兽花钱
				// 存在条件:
				// j - p[i]要不越界,并且在钱数为j - p[i]时,要能通过0~i-1的怪兽,并且钱数组合是有效的。
				if (j >= p[i] && dp[i - 1][j - p[i]] != -1) {
					dp[i][j] = dp[i - 1][j - p[i]] + d[i];
				}
				// 可能性二,不为当前怪兽花钱
				// 存在条件:
				// 0~i-1怪兽在花钱为j的情况下,能保证通过当前i位置的怪兽
				if (dp[i - 1][j] >= d[i]) {
					// 两种可能性中,选武力值最大的
					dp[i][j] = Math.max(dp[i][j], dp[i - 1][j]);
				}
			}
		}
		int ans = 0;
		// dp表最后一行上,dp[N-1][j]代表:
		// 能经过0~N-1的怪兽,且花钱为j(花钱的严格等于j)时的武力值最大是多少?
		// 那么最后一行上,最左侧的不为-1的列数(j),就是答案
		for (int j = 0; j <= sum; j++) {
			if (dp[d.length - 1][j] != -1) {
				ans = j;
				break;
			}
		}
		return ans;
	}
}

1.2.5 对数器

public class MoneyProblem {
	public static int[][] generateTwoRandomArray(int len, int value) {
		int size = (int) (Math.random() * len) + 1;
		int[][] arrs = new int[2][size];
		for (int i = 0; i < size; i++) {
			arrs[0][i] = (int) (Math.random() * value) + 1;
			arrs[1][i] = (int) (Math.random() * value) + 1;
		}
		return arrs;
	}

	public static void main(String[] args) {
		int len = 10;
		int value = 20;
		int testTimes = 10000;
		for (int i = 0; i < testTimes; i++) {
			int[][] arrs = generateTwoRandomArray(len, value);
			int[] d = arrs[0];
			int[] p = arrs[1];
			long ans1 = func1(d, p); //解法1的暴力递归
			long ans2 = minMoney1(d, p); //解法1的动态规划
			
			long ans3 = func2(d, p); //解法2的暴力递归
			long ans4 = minMoney2(d,p);//解法2的动态规划
			if (ans1 != ans2 || ans2 != ans3 || ans1 != ans4) {
				System.out.println("oops!");
			}
		}
	}
}

1.3 小结

如果题目中怪兽能力值的数据范围很大,就选择第二种解法;

如果贿赂怪兽的钱的数据范围很大时,就选择第一种解法。

通常,这两个值的数据范围不会同时很大。

方法的选择就是根据 1 0 8 10^8 108 这个标杆进行的,估计表规模,确定哪种解法能拿下。

2、总结

再举个🌰:某个数组的长度是 N N N,范围是 0 ~ 1 0 12 10^{12} 1012,数组中的每个值 V V V,数据范围是 1 ~ 10000。

那么算法要么是在 N N N 上做二分;要么算法就和 N N N 无关,只和 V V V有关;如果既和 N N N有关,又和 V V V有关,那么只有二分能解决。

要想具备这种能力:

  1. 时间复杂度的分析的基本功扎实 【基本功】
  2. 知道“常数O(1)指令操作控制在108内”这个结论 【结论】
  3. 善于观察,能够从给的输入数据状况来分析从什么方向入手 【刷题练习】

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

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

相关文章

大数据核心技术是什么

大数据的核心层&#xff1a;数据采集层、数据存储与分析层、数据共享层、数据应用层&#xff0c;可能叫法有所不同本质上的角色都大同小异。 大数据的核心技术都包括什么&#xff1f; 1、数据采集 数据采集的任务就是把数据从各种数据源中采集和存储到数据存储上&#xff0c…

多种方法进行去基线处理

目录detrend函数去除基线多项式拟合原函数BEADS 基线处理小波算法经验模态分解&#xff08;EMD&#xff09;参考detrend函数去除基线 detrend函数只能用于去除线性趋势&#xff0c;对于非线性的无能为力。 函数表达式&#xff1a;y scipy.signal.detrend(x): 从信号中删除线…

3.【Linux】安装 elasticsearch-7.10.0 单机版

1.下载 版本 JDK 11ES elasticsearch-7.10.0 jdk安装 下载&#xff1a; wget https://download.java.net/openjdk/jdk11/ri/openjdk-1128_linux-x64_bin.tar.gz配置环境变量&#xff1a;# 编辑配置文件 vim /etc/profile# Java11环境变量配置 export JAVA_HOME/devtools/ja…

【编程语言】AWK 极简教程

1 概述 AWK 是一种解释执行的编程语言。它非常的强大,被设计用来专门处理文本数据。AWK 的名称是由它们设计者的名字缩写而来 —— Afred Aho, Peter Weinberger 与 Brian Kernighan。 由 GNU/Linux 发布的 AWK 版本通常被称之为 GNU AWK,由自由软件基金( Free Software Fou…

《爆肝整理》保姆级系列教程python接口自动化(二十二)--unittest执行顺序隐藏的坑(详解)

简介 大多数的初学者在使用 unittest 框架时候&#xff0c;不清楚用例的执行顺序到底是怎样的。对测试类里面的类和方法分不清楚&#xff0c;不知道什么时候执行&#xff0c;什么时候不执行。虽然或许通过代码实现了&#xff0c;也是稀里糊涂的一知半解&#xff0c;这样还好&am…

2023前端二面手写面试题总结

创建10个标签&#xff0c;点击的时候弹出来对应的序号 var a for(let i0;i<10;i){adocument.createElement(a)a.innerHTMLi<br>a.addEventListener(click,function(e){console.log(this) //this为当前点击的<a>e.preventDefault() //如果调用这个方法&#x…

Nordic nRF芯片FDS模块学习

FDS系统学习 文章目录FDS系统学习一、ROM&#xff0c;RAM&#xff0c;FLASH作用二、ROM,RAM和FLASH在单片中的运作原理三、Flash访问模块FDS用法1. FDS在sdk_config.h中的配置2. fds_register()注册3. fds_record_write()写记录4. fds_record_find()查找5. fds_record_open()读…

PWM实验

目录 一、pwm与RGB LCD 二、硬件原理 1、I.MX6U PWM 频率和占空比 2、原理图与数据手册 3、寄存器 PWM1_PWMCR PWM1_PWMIR​编辑 PWM1_PWMSR​编辑 PWM1_PWMPR​编辑 PWM1_PWMSAR​编辑 三、代码编写 1、编写bsp_backlight.h 2、编写bsp_backlight.c 一、pwm与RGB …

物联网平台源码 物联网源码 springmvc+Mysql+Html

IOT智慧物联网大数据平台源码 物联网平台是一套存在于云端的的软件&#xff0c;提供了一种支持将物联网系统中的设备层、网络层和应用层组织在一起的方案模板&#xff0c;物联网平台现已成为物联网生态系统中最重要的组成部分。 一般来讲&#xff0c;完整的物联网平台主要由以…

Linux C/C++或者嵌入式开发到底有没有35岁危机?

一个读者问了一个问题&#xff1a; 我现在25岁&#xff0c;双非一本本科。在深圳上班&#xff0c;做嵌入式开发&#xff0c;打算走Linux C/C开发&#xff0c;工资目前一般。读了前辈写的很多博客之后&#xff0c;觉得很棒。我现在有一些疑问。 1.最近互联网裁员很厉害嘛&#x…

【selenium自动化测试】如何定位页面元素,及对页面元素的操作方法

selenium元素定位 ​selenium定位元素的方式有8种。 fild_element(by,value)&#xff1a;by表示使用的定位方式&#xff0c;定位方式可以参见By类。value表示值&#xff0c;例如&#xff1a;根据id定位 By.ID&#xff0c;valueid属性的值。该方法返回元素对象&#xff0c;返…

【Linux学习笔记】3.Linux 忘记密码解决方法及远程登录

前言 本章介绍Linux的忘记密码解决方法及远程登录。 Linux 忘记密码解决方法 很多朋友经常会忘记Linux系统的root密码&#xff0c;linux系统忘记root密码的情况该怎么办呢&#xff1f;重新安装系统吗&#xff1f;当然不用&#xff01;进入单用户模式更改一下root密码即可。 …

【Leetcode 剑指Offer】第 4 天 查找算法(简单)

查找剑指 Offer 03. 数组中重复的数字剑指 Offer 53 - I. 在排序数组中查找数字 I二分法题目链接剑指 Offer 03. 数组中重复的数字 题&#xff1a;在一个长度为 n 的数组 nums 里的所有数字都在 0&#xff5e;n-1 的范围内。数组中某些数字是重复的&#xff0c;但不知道有几个数…

一个列表引发的思考(简单版)

最近老板让我按照设计图写一个页面&#xff0c;不嫌丢人的说这是我第一次写页面&#xff0c;哈哈哈。 然后设计图里有一个这样的需求&#xff0c;感觉挺有意思的。 为什么感觉有意思呢&#xff0c;因为这个列表它前面是图片&#xff0c;然后单行和双行的不一样。&#xff08;请…

电子技术——稳定性问题

电子技术——稳定性问题 本节我们讨论稳定性问题。 反馈放大器的传递函数 在考虑频率响应的情况下&#xff0c;开环增益 AAA 通常是关于复频率 sss 的函数 。那么 A(s)A(s)A(s) 就称为 开环传递函数 。同时&#xff0c; β\betaβ 也可能是一个关于复频率 sss 的函数。我们称…

Element表单嵌套树形表格的校验问题

如图&#xff0c;第一次遇到属性表格的校验问题 曾经写过单纯的表格校验是这样的 <el-form ref"forms" :model"forms"><el-table ref"multipleTable" :data"forms.tableData" tooltip-effect"dark" border style&…

关于iframe一些通讯的记录(可适用工作流审批)

一.知识点(1).我们可以通过postMessage(发送方)和onmessage(接收方)这两个HTML5的方法, 来解决跨页面通信问题&#xff0c;或者通过iframe嵌套的不同页面之间的通信a.父页面代码如下<div v-if"src" class"iframe"><iframeref"iframe"id…

SpringBoot集成Redis实现分布式会话

在单体应用的时代&#xff0c;Session 会话直接保存在服务器中&#xff0c;实现非常简单&#xff0c;但是随着微服务的流行&#xff0c;现代应用架构基本都是分布式架构&#xff0c;请求随机的分配到后端的多个应用中&#xff0c;此时session就需要共享&#xff0c;而存储在red…

【运动控制】CNC三轴小线段路径规划

CNC三轴小线段路径规划 文章目录CNC三轴小线段路径规划一、项目说明二、具体实现1、速度规划2、小线段插补3、运动学逆解刀轴插补点4、差分处理得到实际的速度和加速度5、加速度滑动平均6、实现的效果如图所示三、Reference写在前面&#xff0c;本文是作为一个练手小项目的总结…

2023年阿里云ECS服务器S6/C6/G6/N4/R6/sn2ne/sn1ne/se1ne处理器CPU性能详解

阿里云ECS服务器S6/C6/G6/N4/R6/sn2ne/sn1ne/se1ne处理器CPU性能怎么样&#xff1f;阿里云服务器优惠活动机型有云服务器S6、计算型C6、通用型G6、内存型R6、云服务器N4、云服务器sn2ne、云服务器sn1ne、云服务器se1ne处理器CPU性能详解及使用场景说明。 1、阿里云服务器活动机…