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 是丑数。
- n 不超过1690。
使用三个指针 i2, i3和 i5,标记因子2,3,5下一个要去×的数的下标
- 在 2×nums[i2],3×nums[i3] 和 5×nums[i5] 选出最小的丑数,添加到数组nums中。
- 将该丑数对应的因子指针往前走一步。
- 重复该步骤直到计算完 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% 的用户