动态规划IV (118、119、198、213、337)

CP118 杨辉三角

题目描述:

给定一个非负整数 numRows生成「杨辉三角」的前 numRows 行。在「杨辉三角」中,每个数是它左上方和右上方的数的和。

学习记录:

思想就是没有思想,的杨辉三角,但是注意resize的用法和初始化的方法!

//题解
class Solution {
public:
    vector<vector<int>> generate(int numRows) {
        vector<vector<int>> ret(numRows);
        for (int i = 0; i < numRows; ++i) {
            ret[i].resize(i + 1);
            ret[i][0] = ret[i][i] = 1;
            for (int j = 1; j < i; ++j) {
                ret[i][j] = ret[i - 1][j] + ret[i - 1][j - 1];
            }
        }
        return ret;
    }
};

CP119 杨辉三角II

题目描述:

给定一个非负索引 rowIndex,返回「杨辉三角」的第 rowIndex 行。在「杨辉三角」中,每个数是它左上方和右上方的数的和。

学习记录:

由于刚刚那个没写,这个就写了一下,如果按第一种方法直接开个二维数组是OK的,然后就想肯定是可以用一维的,但是如果从后往前遍历就存在问题,例如1 2 1,要计算1+2,2+1,,那么1+2要存在第二个位置的话,计算2+1就没办法计算了,中间的2就无了。但是反向遍历却是OK的,还考虑1 2 1,倒着来,先计算2+1存在第三个位置,此时第二个位置的2还是有的,可以把1+2存在第二个位置,能很好的计算!

class Solution {
public:
    vector<int> getRow(int rowIndex) {

        vector<int> result(rowIndex+1);
        result[0]=1;

        if(rowIndex==0) return result;

        for(int i=1;i<=rowIndex;i++)
        {
            result[i]=1;
            for(int j=i-1;j>0;j--)
            {
                result[j]=result[j-1]+result[j];
            }
        }
        return result;
    }
};

CP198 打家劫舍

题目描述:

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

学习记录:

第一个想法就是,每个房子有两种选择,偷或者不偷,用两个变量来记录,然后这间偷=上一间不偷+这间偷,但是显然存在一个问题,可以连续两个房子不偷的,所以肯定是解答错误的。

class Solution {
public:
    int rob(vector<int>& nums) {
        int length=nums.size();
        int t=nums[0];int f=0;
        for(int i=1;i<length;i++)
        {
            int temp=t;
            t=f+nums[i];
            f=temp;
        }
        return t>f ? t : f;
    }
};

然后的想法是,每间房子有两种选择,偷或者不偷,用两个变量来记录,记录的是,这间偷或者不偷情况下能获得最多的钱,前面已经说了,少考虑了情况,也就是说状态转移方程会发生改变。

注意:由于非负,所以不断后移的情况下,每间偷和不偷一定都是在增加的

这间偷=max(上一间不偷+这间的钱,上一间偷);

这间不偷=max(上一间不偷,上一天偷);

class Solution {
public:
    int rob(vector<int>& nums) {
        int length=nums.size();

        int t=nums[0];//偷
        int f=0;//不偷
        for(int i=1;i<length;i++)
        {
            int temp=t;//临时存一下昨天偷的值
            t=max(t,f+nums[i]);
            f=max(temp,f);
        }
        
        return t>f ? t : f;
    }
};

虽然写出来了,但是去看了一下题解,还是想复杂了,只需要记录到每间后的最大金额就行,无论这间你选择偷不偷都行,只记录最大就行。然后数组也可以变成三个存储空间

看了这个后其实有个移位,如果偷第k间屋子,用的是dp[i-2]+nums[i],但是如果在dp[i-1]的地方选择的是不偷,为什么不用dp[i-1]呢?思考:如果i-1偷达到最大,那么就应该用i-2的最大来加这个是毫无疑问的;如果i-1在不偷的时候达到最大,说明一定是之前的一个组合使得结果最大,那么这个最大在i-2也是可以达到的,也就是说如果i-1不偷,那必然存在dp[i-1]=dp[i-2],所以综合两种情况,在偷i的时候用i-2处的最大值就行了,避免我们判断i-1处是否偷。

class Solution {
public:
    int rob(vector<int>& nums) {
        if (nums.empty()) {
            return 0;
        }
        int size = nums.size();
        if (size == 1) {
            return nums[0];
        }
        vector<int> dp = vector<int>(size, 0);
        dp[0] = nums[0];
        dp[1] = max(nums[0], nums[1]);
        for (int i = 2; i < size; i++) {
            dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
        }
        return dp[size - 1];
    }
};

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/house-robber/solution/da-jia-jie-she-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

CP213 打家劫舍II

题目描述:

你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。

学习记录:

刮大风,下大雨,8级雷暴,只想睡觉,脑子一片空白

但是为什么第一间和最后一间一定要选一间?思考连续的两间是否必偷一间,答案是不一定的,13131,首尾就都不偷,但是这对我们截断没有影响,也就是说,不是第一间和最后一间都要偷,但是这两间中最多只能偷一间,所以我们可以截成两个部分去思考。

class Solution {
public:
    int robRange(vector<int>& nums, int start, int end) {
        int first = nums[start], second = max(nums[start], nums[start + 1]);
        for (int i = start + 2; i <= end; i++) {
            int temp = second;
            second = max(first + nums[i], second);
            first = temp;
        }
        return second;
    }

    int rob(vector<int>& nums) {
        int length = nums.size();
        if (length == 1) {
            return nums[0];
        } else if (length == 2) {
            return max(nums[0], nums[1]);
        }
        return max(robRange(nums, 0, length - 2), robRange(nums, 1, length - 1));
    }
};

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/house-robber-ii/solution/da-jia-jie-she-ii-by-leetcode-solution-bwja/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

CP337 打家劫舍III

题目描述:

小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root 。除了 root 之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果 两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。给定二叉树的 root 。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额 。

学习记录:不会

class Solution {
public:
    unordered_map <TreeNode*, int> f, g;

    void dfs(TreeNode* node) {
        if (!node) {
            return;
        }
        dfs(node->left);
        dfs(node->right);
        f[node] = node->val + g[node->left] + g[node->right];
        g[node] = max(f[node->left], g[node->left]) + max(f[node->right], g[node->right]);
    }

    int rob(TreeNode* root) {
        dfs(root);
        return max(f[root], g[root]);
    }
};

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/house-robber-iii/solution/da-jia-jie-she-iii-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

改进为:

struct SubtreeStatus {
    int selected;
    int notSelected;
};

class Solution {
public:
    SubtreeStatus dfs(TreeNode* node) {
        if (!node) {
            return {0, 0};
        }
        auto l = dfs(node->left);
        auto r = dfs(node->right);
        int selected = node->val + l.notSelected + r.notSelected;
        int notSelected = max(l.selected, l.notSelected) + max(r.selected, r.notSelected);
        return {selected, notSelected};
    }

    int rob(TreeNode* root) {
        auto rootStatus = dfs(root);
        return max(rootStatus.selected, rootStatus.notSelected);
    }
};

还是状态的选择,但是这个也用到分治的思想,变成叶节点,但是注意就是之前我们是用i来索引的,但是这里我们有的是指针,也就是说我们需要找到指针和数字的对应,也就是说hash表!!代码还是比较好理解的,但是还是学习很多。1.状态的选择,2.指针和数字的对应

PS:我这个小菜鸟居然开始有funs了,虽然都是通过用户推荐关注的,但是还是觉得很欣慰,但是UP自己写是为了自己学习,很多题解是copy的官网题解和大佬的,不是抄袭,自留学习用,不妥请私信删除,非常抱歉,感谢大家的理解!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值