LeetCode 198 打家劫舍

LeetCode 198 打家劫舍

https://leetcode.cn/problems/house-robber/description/

普通递归

对于一维数组,子问题可以分解为 长度更小的问题,如何分解呢?可以从第一个或最后一个开始分解。

对于本问题输入数组长度为 len 是否可以分解为长度为 len-1,len-2,len-3 这种长度小的问题呢?

可以关心最后一个(或第一个),这个打劫 那么调用下层 len -2 ,这个不打那么调用下层 len -1

class Solution {

public:

    int robb(vector<int>& nums,int end){

        if(end == 0) return nums[0];

        if(end==1) return max(nums[0],nums[1]);

        return max(robb(nums,end-1),nums[end]+robb(nums,end-2));

    }

    int rob(vector<int>& nums) {

        return robb(nums,nums.size()-1);

    }

};

但是输入数组一多就超时了。

记忆化递归

注意到有些 子树 重复了,这些可以记录下来,下次再求值的时候就直接用。

class Solution {

public:

    vector<int> res;

    int robb(vector<int>& nums,int end){

        if(res[end]!=-1) return res[end];

        if(end == 0) return nums[0];

        if(end==1) return max(nums[0],nums[1]);

        res[end] = max(robb(nums,end-1),nums[end]+robb(nums,end-2));

        return res[end];

    }

    int rob(vector<int>& nums) {

        res = vector<int>(nums.size(),-1);

        return robb(nums,nums.size()-1);

    }

};

记忆化递归->动态规划

dfs 就是上面的递归函数。f 数组可以看成递归函数的返回值数组。

class Solution {

public:

    int rob(vector<int>& nums) {

        vector<int> fun_res(nums.size(),-1);

        fun_res[0] = nums[0];

        fun_res[1] = max(nums[0],nums[1]);

        for(int i =2;i<nums.size();i++){

            fun_res[i] = max(fun_res[i-1],fun_res[i-2]+nums[i]);

        }

        return fun_res[nums.size()-1];

    }

};

但是不完美,有些数组只有一个值就会报错,可以处理一下数组下标为负数的情况。

class Solution {

public:

    int rob(vector<int>& nums) {

        vector<int> fun_res(nums.size(),-1);

        fun_res[0] = nums[0];

        // fun_res[1] = max(nums[0],nums[1]);

        for(int i =1;i<nums.size();i++){

            fun_res[i] = max(fun_res[i-1],(i-2>=0?fun_res[i-2]:0)+nums[i]);

        }

        return fun_res.back();

    }

};