【leetcode】dp---中等(1)213. 打家劫舍 II_dp两种初始(2)**221. 最大正方形_dp三个角最小值(3)**264. 丑数 II_dp多指针标记_序列

213、你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

示例 1:

输入: [2,3,2]
输出: 3
解释: 你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。

示例 2:

输入: [1,2,3,1]
输出: 4
解释: 你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。

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

两种初始。a]0偷1不偷,此时n-1必不偷。b]0不偷1偷,此时n-1可偷。

// dp[i]:到i房间偷到的最大金额
// 状态转移:1)房i不偷;2)房i偷; 3)两种初始。a]0偷1不偷,此时n-1必不偷。b]0不偷1偷,此时n-1可偷。
// dp[i] = max(dp[i-1], dp[i-2] + nums[i]);
class Solution {
public:
    int rob(vector<int>& nums) {
        int n = nums.size();
        if(n == 0) return 0;
        if(n == 1) return nums[0];
        vector<int> dp(n, 0);
        int ans = max(nums[0], nums[1]);
        // 偷0,不偷1。 n-1无法偷
        dp[0] = nums[0];
        dp[1] = nums[0];
        for(int i = 2; i < n-1; i++){
            dp[i] = max(dp[i-1], dp[i-2] + nums[i]);
            ans = max(ans, dp[i]);
        }
        // 偷1, 不偷0。 n-1可以偷
        dp.resize(n, 0);
        dp[0] = 0;
        dp[1] = nums[1];
        for(int i = 2; i < n; i++){
            dp[i] = max(dp[i-1], dp[i-2] + nums[i]);
            ans = max(ans, dp[i]);
        }
        return ans;
    }
};

结果:

执行用时:4 ms, 在所有 C++ 提交中击败了45.13% 的用户

内存消耗:8.1 MB, 在所有 C++ 提交中击败了14.07% 的用户

 

221、在一个由 0 和 1 组成的二维矩阵内,找到只包含 1 的最大正方形,并返回其面积。

示例:

输入: 

1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0

输出: 4

dp(i,j) 表示以 (i,j)为右下角,且只包含 1 的正方形的边长最大值

dp(i,j)=min(dp(i−1,j),dp(i−1,j−1),dp(i,j−1))+1   公式的原理

// dp[i][j]:(i,j)位置包含的最大全1正方形的边长
// dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1
class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
        int m = matrix.size();
        if(m == 0) return 0;
        int n = matrix[0].size();
        if(n == 0) return 0;
        int ans = matrix[0][0] - '0';
        vector<vector<int>> dp(m, vector<int>(n, 0));
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                if(i == 0 || j == 0) dp[i][j] = matrix[i][j] - '0';
                else if(matrix[i][j] == '1') dp[i][j] = min(dp[i-1][j-1], min(dp[i-1][j], dp[i][j-1])) + 1;
                ans = max(ans, dp[i][j]);
            }
        }
        return ans * ans;
    }
};

结果:

执行用时:68 ms, 在所有 C++ 提交中击败了6.29% 的用户

内存消耗:11.8 MB, 在所有 C++ 提交中击败了61.27% 的用户

 

264、编写一个程序,找出第 n 个丑数。

丑数就是质因数只包含 2, 3, 5 的正整数。

示例:

输入: n = 10
输出: 12
解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。

说明:  

  1.     1 是丑数。
  2.     n 不超过1690。

使用三个指针 i2​, i3和 i5​,标记因子2,3,5下一个要去×的数的下标

  1. 在 2×nums[i2],3×nums[i3] 和 5×nums[i5] 选出最小的丑数,添加到数组nums中。
  2. 将该丑数对应的因子指针往前走一步。
  3. 重复该步骤直到计算完 1690 个丑数。

dp[i] = min(dp[i2] * 2, min(dp[i3] * 3, dp[i5] * 5));

// dp[i]:第i个丑数
// 状态转移:第i个丑数等于之前的某个丑数乘上2/3/5,得到的最小值
// dp[i] = min(dp[i2] * 2, min(dp[i3] * 3, dp[i5] * 5));
class Solution {
public:
    int nthUglyNumber(int n) {
        vector<int> dp(n + 1, 0);
        dp[0] = 1;
        int i2 = 0, i3 = 0, i5 = 0; // 因子2,3,5下一个要去×的数的下标
        for(int i = 1; i < n; i++){
            dp[i] = min(dp[i2] * 2, min(dp[i3] * 3, dp[i5] * 5));
            if(dp[i] == dp[i2] * 2) i2++;
            if(dp[i] == dp[i3] * 3) i3++;
            if(dp[i] == dp[i5] * 5) i5++;
        }
        return dp[n-1];
    }
};

结果:

执行用时:16 ms, 在所有 C++ 提交中击败了62.81% 的用户

内存消耗:7.6 MB, 在所有 C++ 提交中击败了68.97% 的用户

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值