当前位置: 首页 > news >正文

网站互点联盟建设网站主机免费的怎么下载

网站互点联盟,建设网站主机免费的怎么下载,网站推广活动策划,wordpress模板字体修改字体动态规划–Day03–打家劫舍–198. 打家劫舍,213. 打家劫舍 II,2320. 统计放置房子的方式数 今天要训练的题目类型是:【打家劫舍】,题单来自灵艾山茶府。 掌握动态规划(DP)是没有捷径的,咱们唯一…

动态规划–Day03–打家劫舍–198. 打家劫舍,213. 打家劫舍 II,2320. 统计放置房子的方式数

今天要训练的题目类型是:【打家劫舍】,题单来自@灵艾山茶府。

掌握动态规划(DP)是没有捷径的,咱们唯一能做的,就是投入时间猛猛刷题。

动态规划要至少刷100道才算入门!

记忆化搜索是新手村神器。方便理解,写完之后可以转译成递推。

但是有些题目只能写递推,才能优化时间复杂度。熟练之后直接写递推也可以。

198. 打家劫舍

方法:记忆化搜索(递归)

思路:

和爬楼梯几乎是同一个模板的。爬楼梯是memo[i] = res1 + res2;,而打家劫舍是memo[i] = Math.max(res1, res2);

后来忽然发现了一个细微的差别,爬楼梯,缓存一般是开n+1位,而打家劫舍缓存一般开n位就够了。

  1. 使用memo记忆,缓存已经探索过的节点
  2. 从数组最后一个值开始往前探索
    • 递归结束判断:如果索引超出范围,则返回
    • 如果memo有值,用缓存值
    • 对于当前探索的i这个节点,能不能偷,有两个情况:
      • 情况一:偷i-1家,那么i家就不能偷(递归进去探索i-1节点)
      • 情况二:偷i-2家,那么i家也能偷(递归进去探索i-2节点)
      • 返回两种情况的较大值,顺便保存到记忆
class Solution {public int rob(int[] nums) {int n = nums.length;// 记忆(缓存),默认未使用标志为-1int[] memo = new int[n];Arrays.fill(memo, -1);// 从索引n-1开始搜索(也就是数组的最后一个值)return dfs(n - 1, nums, memo);}private int dfs(int i, int[] nums, int[] memo) {// 索引超出范围,返回if (i < 0) {return 0;}// 如果已经判断过这种情况了,直接用记忆(缓存)if (memo[i] != -1) {return memo[i];} else {// 情况一:偷i-1家,那么i家就不能偷// 情况二:偷i-2家,那么i家也能偷int res1 = dfs(i - 1, nums, memo);int res2 = dfs(i - 2, nums, memo) + nums[i];// 返回两种情况的较大值,顺便保存到记忆memo[i] = Math.max(res1, res2);}return memo[i];}
}

从dfs函数来看,一进去先判断索引是否超出范围,超出了则返回。其实是浪费多了一次资源(因为调用函数要压栈,出栈等,时间空间都变慢了)

可以改成这样:先判断索引,再考虑调用函数:

private int dfs(int i, int[] nums, int[] memo) {if (memo[i] != -1) {return memo[i];} else {// 先判断索引合法,再调用函数int res1 = 0;if (i - 1 >= 0) {res1 = dfs(i - 1, nums, memo);}// res2要赋值为nums[i]int res2 = nums[i];if (i - 2 >= 0) {res2 = dfs(i - 2, nums, memo) + nums[i];}memo[i] = Math.max(res1, res2);}return memo[i];
}

注意,这里res2要默认赋值为nums[i]。因为这是一个决策,是决定偷i-2,那么i家先偷了,再去i-2,然后发现i-2没有人住(超出索引范围),那么i家我也偷到了。

如果写成这样是错的:

private int dfs(int i, int[] nums, int[] memo) {if (memo[i] != -1) {return memo[i];} else {int res1 = 0;int res2 = 0;if (i - 1 >= 0) {res1 = dfs(i - 1, nums, memo);}if (i - 2 >= 0) {res2 = dfs(i - 2, nums, memo) + nums[i];}memo[i] = Math.max(res1, res2);}return memo[i];
}

方法:动态规划(递推)

思路:

递推要初始化,因为f[i]需要依赖f[i-1]和f[i-2],所以要初始化前两个数,还要特判n==1的情况。

class Solution {public int rob(int[] nums) {int n = nums.length;// 如果只有一家,直接偷,返回。if (n == 1) {return nums[0];}int[] f = new int[n];// 递推要初始化,因为f[i]需要依赖f[i-1]和f[i-2],所以要初始化前两个数f[0] = nums[0];f[1] = Math.max(nums[0], nums[1]);// 从第三个数开始遍历for (int i = 2; i < n; i++) {// 情况一:偷i-1家,那么i家就不能偷// 情况二:偷i-2家,那么i家也能偷int res1 = f[i - 1];int res2 = f[i - 2] + nums[i];// 偷较大值f[i] = Math.max(res1, res2);}// 最后的结果,在最后一家判断完之后,包含了所有的情况。// 所以答案在最后一个索引的位置。return f[n - 1];}
}

思路:

把f数组索引直接+2。上一篇代码的f[0]的值,放到这一题代码的f[2]的位置。

不管f[0]和f[1],直接不用他们。

class Solution {public int rob(int[] nums) {int n = nums.length;int[] f = new int[n + 2];for (int i = 0; i < n; i++) {f[i + 2] = Math.max(f[i + 1], f[i] + nums[i]);}return f[n + 1];}
}

思路:

空间优化的写法。

class Solution {public int rob(int[] nums) {int f0 = 0;int f1 = 0;for (int x : nums) {int newF = Math.max(f1, f0 + x);f0 = f1;f1 = newF;}return f1;}
}

这些都是写完之后的优化版本,如果第一次写,不要想复杂的,先按照自己内心第一思路,把题目写完先,再想优化。

213. 打家劫舍 II

方法:动态规划(递推)

思路:

  • 特判索引0位置,把剩余位置变为非循环数组进行操作。
  • 索引0位置只有两种选择,偷或者不偷。
    • 偷索引0,那么索引1和索引n-1不能偷。问题变为从索引2到n-2的非循环数组。
    • 不偷索引0。问题变为从索引1到n-1的非循环数组。
  • 取二者较大值
class Solution {public int rob(int[] nums) {int n = nums.length;// 偷索引0,那么索引1和索引n-1不能偷。问题变为从索引2到n-2的非循环数组。int res1 = nums[0] + rob1(nums, 2, n - 2);// 不偷索引0。问题变为从索引1到n-1的非循环数组。int res2 = rob1(nums, 1, n - 1);// 取二者较大值return Math.max(res1, res2);}// 上一题的空间优化版本private int rob1(int[] nums, int start, int end) {int f0 = 0;int f1 = 0;// [start,end] 左闭右闭for (int i = start; i <= end; i++) {int newF = Math.max(f1, f0 + nums[i]);f0 = f1;f1 = newF;}return f1;}
}

2320. 统计放置房子的方式数

方法:动态规划(递推)

思路:

  • 两边互相独立,求一边,最后f[n] * f[n]即可。
  • 初始化f[0]和f[1]。如果没有空地,只有不放这1种选择;如果只有一块空地,有放和不放2种选择。
  • 对于每个f[i]:
    • 情况一:如果不放f[i]的话,f[i-1]可放可不放
    • 情况二:如果放f[i]的话, f[i-2]可放可不放
    • 两种情况加起来,就是f[i]可放可不放
  • 最后返回结果时:
    • 注意,两个MOD相加,不会溢出int。但是两个MOD相乘,会溢出int
    • 所以要先转为long,相乘,取模,后再转为int
class Solution {public int countHousePlacements(int n) {// 两边互相独立,求一边,最后f[n] * f[n]即可final int MOD = 1000000007;int[] f = new int[n + 2];// 初始化。如果没有空地,只有不放这1种选择;如果只有一块空地,有放和不放2种选择。f[0] = 1;f[1] = 2;for (int i = 2; i <= n; i++) {// 情况一:如果不放f[i],f[i-1]可放可不放// 情况二:如果放f[i], f[i-2]可放可不放// 两种情况加起来,就是f[i]可放可不放f[i] = (f[i - 1] + f[i - 2]) % MOD;}// 注意,两个MOD相加,不会溢出int。但是两个MOD相乘,会溢出int// 所以要先转为long,相乘,取模,后再转为intreturn (int) ((long) f[n] * f[n] % MOD);}
}

总感觉这道题跟《打家劫舍》没什么关系,反而像是《爬楼梯》。每个位置都可爬可不爬,然后结果加起来。f[i] = (f[i - 1] + f[i - 2])。初步是这么想,多做题,回头再看看。

关于取模运算,可以看@灵艾山茶府的这篇文章:模运算的世界:当加减乘除遇上取模。

http://www.dtcms.com/a/493461.html

相关文章:

  • 网站制作小工具沈阳建设工程信息网 找到中项网
  • 网站添加悬浮二维码网站底部源码
  • 企业标准版网站建设网站模板下载源码
  • 代驾网站开发乐清网络公司哪家好
  • 海南 网站 建设制作网页用什么进行页面布局
  • 网站从建设到运行要多少钱动漫做的游戏 迅雷下载网站
  • 网站提供商基于php的家具公司网站
  • 网站建设伍首选金手指小程序流量点击推广平台
  • 建立网站的作用合肥做网站的公司
  • 网站标题和描述优化网站建设字体
  • 诚通凯胜生态建设有限公司网站php建站软件
  • app与微网站的区别是什么意思好用app制作
  • php 英文网站模板响应式网站开发要注意哪些
  • 怎么知道网站的空间是谁做的彩票网站开发违法
  • 自助健站大同推广型网站建设
  • 合肥瑶海区网站建设费用网络营销的常见方式有哪些
  • asp购物网站客户查看购物车网络推广哪个平台最好
  • 中国建设教育协会培训中心网站网站备案拍照 广州
  • 黄石手机网站建设源代码网站和模板做的区别
  • 广州网站外贸推广全国家装官网
  • 台州做网站需要多少钱yum nginx wordpress
  • 用vs做网站 怎么安装百度蜘蛛抓取新网站
  • 黄页网站 phpwordpress工单插件
  • 介绍几个能进去的a站深圳网站建设多少钱
  • 写作网站挣钱对比网页设计与制作教程第三版张兵义
  • 网站开发进度在什么网站做公司人员增减
  • 网页和网站区别是什么免费海外网络连接器
  • 厦门网页建站申请比较好wordpress 右侧广告
  • 专业html5网站建设临沂建设局网站
  • 上海建设网站的网站电子商务网站的功能