198. House Robber 关于动态规划问题(Dynamic programming)的学习、思考与记录

本文以LeetCode中的House Robber问题为例,详细介绍了如何通过动态规划解决问题,并逐步优化算法,包括递归、带备忘录的递归、自底向上的迭代方法及减少空间复杂度的技巧。

动态规划(Dynamic programming)

定义

任何数学递推公式都可以直接转换为递归算法,但是基本现实是编译器常常不能正确对待递归算法,结果导致低效的程序。当怀疑出现这样的情况时,我们必须再给编译器提供一些帮助,即将递归算法转换为非递归算法,让后者把那些子问题的答案系统的记录在一个表内。利用这种方法的一种技巧叫做动态规划。

以LeetCode.198. House Robber为例进行一下算法的优化。

大多数的问题可以按照下面的顺序进行解决:
1.找到递归关系,得到递归关系式。
2.自顶向下的递归。(top-down)
3.自顶向下的递归 + 存储记录。(top-down)
4.转化为非递归 + 存储记录。(自下向上 bottom-up)
5.非递归 + n 个变量存储(bottom-up)

第一步:找到递归关系。
题中盗贼有两个选择:
(1)洗劫当前的房子 i;(2)不洗劫当前的房子。
若选(1)则意味着他不能洗劫前一个房子i-1,但是他可以对前面的i-2个房子进行有选择的洗劫。
若选(2)则意味着他可以对前面的i-1个房子进行有选择的洗劫。

因此递归关系为:

rob(i) = Math.max( rob(i - 2) + currentHouseValue, rob(i - 1) )

第二步:自顶向下的递归。(top-down)
将第一步的递归关系式转换如下:

public int rob(int[] nums) {
    return rob(nums, nums.length - 1);
}
private int rob(int[] nums, int i) {
    if (i < 0) {
        return 0;
    }
    return Math.max(rob(nums, i - 2) + nums[i], rob(nums, i - 1));
}

由于上述算法会重复的处理相同的子问题导致计算复杂度会随输入规模快速增长,问题多一个输入,那么计算的规模就要乘上2,所以时间复杂度为2^n这个级别,所以此方案放在leetcode上会超时,因此需要优化。

第三步:自顶向下的递归 + 存储记录。(top-down)

class Solution {
    int[] memo;
    public int rob(int[] nums) {
        memo = new int[nums.length];
        Arrays.fill(memo, -1);
        return rob(nums, nums.length - 1);
    }

    private int rob(int[] nums, int i) {
        if (i < 0) {
            return 0;
        }
        //这一步的判断可以防止重复计算相同的子问题
        if (memo[i] >= 0) {
            return memo[i];
        }
        int result = Math.max(rob(nums, i - 2) + nums[i], rob(nums, i - 1));
        memo[i] = result;
        return result;
    }
}

这个算法就好很多了,时间复杂度和空间复杂度都为O(n),下一步优化可以试着摆脱递归堆栈。

第四步:转化为非递归 + 存储记录。(自下向上 bottom-up)
主体还是上面提到的那个关系,只是我们将子问题的结果放在了一个临时数组中。临时数组中存放的都是子问题的最优解。比如memo [1]里面存放的就是前两个元素中最大值,即最优解。当计算前三个数中最优解的时候,我只要做一个选择,即要不要选择nums[2]这个元素,选择的话,那么我就从memo [2-2]中得到最优解,加起来就是当前最优解,不选择的话,就从memo [2-1]中选择最优解。依次下去,tmp中最后一个值就是整个序列中组合的最优解了。

这里注意一下,这里其实是记忆化搜索的思想来实现的,我们可以注意到,其实是自顶向下来看的,从第一个数字来一直推到最后。然而动态规划的思想是从底向上的,参见第一个递归版本的实现。我们先考虑的是最终的n,而不是考虑从0开始。所以在设计思想上是有所区别的,但是又是非常类似,有的人将他们归位一类,我想,它们在大多数场景下可以互换的化,可以认为都是广义上的DP算法吧,因为DP毕竟只是一种思想,正过来实现反过来实现也未尝不可。

我们用一个数组来存放子问题的最优解,大大降低了时间复杂度,leetcode上也顺利通过。其实这个是一种记忆化搜索的思想,上面这个用了一个数组,其实完全没有必要用数组,用两个变量即可。

class Solution {
    public int rob(int[] nums) {
        if(nums.length <= 0){
            return 0;
        }
        if(nums.length == 1){
            return nums[0];
        }
        int[] memo = new int[nums.length];
        memo[0] = nums[0];
        memo[1] = nums[0] > nums[1] ? nums[0] : nums[1];
        for(int i=2;i<nums.length;i++){
            int A = memo[i-2] + nums[i];
            int B = memo[i-1];
            int max = A > B ? A : B;
            memo[i] = max;
        }
        return memo[nums.length-1];
    }
}

第五步:.非递归 + n 个变量存储(bottom-up)

class Solution {
    public int rob(int[] nums) {
        if(nums.length <= 0){
            return 0;
        }
        if(nums.length == 1){
            return nums[0];
        }
        
        int a = nums[0];
        int b = nums[0] > nums[1] ? nums[0] : nums[1];
        for(int i=2;i<nums.length;i++){
            int A = a + nums[i];
            int B = b;
            int max = A > B ? A : B;
            a = b;
            b = max;
        }
        return b;
    }
}
成都市作为中国西部地区具有战略地位的核心都市,其人口的空间分布状况对于城市规划、社会经济发展及公共资源配置等研究具有基础性数据价值。本文聚焦于2019年度成都市人口分布的空间数据集,该数据以矢量格式存储,属于地理信息系统中常用的数据交换形式。以下将对数据集内容及其相关技术要点进行系统阐述。 Shapefile 是一种由 Esri 公司提出的开放型地理空间数据格式,用于记录点、线、面等几何要素。该格式通常由一组相互关联的文件构成,主要包括存储几何信息的 SHP 文件、记录属性信息的 DBF 文件、定义坐标系统的 PRJ 文件以及提供快速检索功能的 SHX 文件。 1. **DBF 文件**:该文件以 dBase 表格形式保存各地理要素相关联的属性信息,例如各区域的人口统计数值、行政区划名称及编码等。这类表格结构便于在各类 GIS 平台中进行查询编辑。 2. **PRJ 文件**:此文件明确了数据所采用的空间参考系统。本数据集基于 WGS84 地理坐标系,该坐标系在全球范围内广泛应用于定位空间分析,有助于实现跨区域数据的准确整合。 3. **SHP 文件**:该文件存储成都市各区(县)的几何边界,以多边形要素表示。每个多边形均配有唯一标识符,可属性表中的相应记录关联,实现空间数据统计数据的联结。 4. **SHX 文件**:作为形状索引文件,它提升了在大型数据集中定位特定几何对象的效率,支持快速读取显示。 基于上述数据,可开展以下几类空间分析: - **人口密度评估**:结合各区域面积对应人口数,计算并比较人口密度,识别高密度低密度区域。 - **空间集聚识别**:运用热点分析(如 Getis-Ord Gi* 统计)或聚类算法(如 DBSCAN),探测人口在空间上的聚集特征。 - **空间相关性检验**:通过莫兰指数等空间自相关方法,分析人口分布是否呈现显著的空间关联模式。 - **多要素叠加分析**:将人口分布数据地形、交通网络、环境指标等其他地理图层进行叠加,探究自然人文因素对人口布局的影响机制。 2019 年成都市人口空间数据集为深入解析城市人口格局、优化国土空间规划及完善公共服务体系提供了重要的数据基础。借助地理信息系统工具,可开展多尺度、多维度的定量分析,从而为城市管理学术研究提供科学依据。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值