第十九天
我使用的C++,错误的地方请见谅,文章初衷仅用来督促本人学习,如果恰巧能够给你带来帮助,我会十分开心。
一、70. 爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
class Solution {
public:
int climbStairs(int n) {
//可以得到的是爬到第n劫的方法数是第n - 1步与第n - 2步方法之和
int q = 0, p = 0, r = 1;
for (int i = 0; i < n; ++i){
q = p;
p = r;
r = q + p;
}
return r;
}
};
先动手计算一下,或许可以得到很多启发(数学)
动态规划题目,也可以使用递归来实现,
class Solution {
public:
int climbStairs(int n) {
//可以得到的是爬到第n劫的方法数是第n - 1步与第n - 2步方法之和
if (n == 1){
return 1;
}
if (n == 2){
return 2;
}
return climbStairs(n - 1) + climbStairs(n - 2);
}
};
会超出时间限制,原因是重复计算,时间复杂度太高,所以定义一个数组来记忆
class Solution {
public:
int climbStairs(int n) {
//可以得到的是爬到第n劫的方法数是第n - 1步与第n - 2步方法之和
int *memo = new int[n + 1];//定义一个记忆数组
return climb(n, memo);
}
int climb(int n, int memo[]){
if (memo[n] > 0){
return memo[n];//如果被计算过,则直接输出
}
else if (n == 1){
memo[n] = 1;
}
else if (n == 2){
memo[n] = 2;
}
else {
memo[n] = climb(n - 1, memo) + climb(n - 2, memo);
}
return memo[n];
}
};
二、198. 打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/house-robber
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
出现了,和之前一道周赛的题目类似,
对于k间房,因为相邻两个房间不能都偷,所以对于第k间房,可以有两种选择:
1、不偷第k间房,则能偷到的金额为在前k - 1间房能偷到的金额
2、不偷第k间房,则能偷的金额为前k - 2间房能偷得的金额加上第k间的金额
这两个选项中金额高的为输出
dp[i]=max(dp[i−2]+nums[i],dp[i−1])
这种题目都需要上手先计算归纳一下,答案往往显而易见
class Solution {
public:
int rob(vector<int>& nums) {
if (nums.empty()){
return 0;
}
if (nums.size() == 1){
return nums[0];
}
int n = nums.size();
vector<int> dp = vector<int>(n, 0);
dp[0] = nums[0];
dp[1] = max(nums[0], nums[1]);
for (int i = 2; i < n; ++i){
dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
}
return dp[n - 1];
}
};
三、120. 三角形最小路径和
给定一个三角形 triangle ,找出自顶向下的最小路径和。
每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 i 或 i + 1 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/triangle
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
//只能三角形移动,所以如果没有相同元素的话,路径是唯一的,如果有相同元素且刚好在三角形的两个脚,怎么办?遍历每一条到达最后一行的路径,找到最小解
int n = triangle.size();
vector<vector<int>> ans(n, vector<int>(n));
ans[0][0] = triangle[0][0];
for (int i = 1; i < n; ++i){
ans[i][0] = ans[i - 1][0] + triangle[i][0];
for (int j = 1; j < i; ++j){
ans[i][j] = min(ans[i - 1][j - 1], ans[i - 1][j]) + triangle[i][j];
}
ans[i][i] = ans[i - 1][i - 1] + triangle[i][i];
}
return *min_element(ans[n - 1].begin(), ans[n - 1].end());
}
};
动态规划这类题目需要先从最基本的情况自己递推一下,然后得出递推公式,在对边界条件进行界定
四、231. 2 的幂
给你一个整数 n,请你判断该整数是否是 2 的幂次方。如果是,返回 true ;否则,返回 false 。
如果存在一个整数 x 使得 n == 2x ,则认为 n 是 2 的幂次方。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/power-of-two
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
若一个数为2的幂,当且仅当其二进制表示中只有一个1,n > 0所以只要判断这一点即可
有两种方法,第一种是利用n & (n - 1)来移除最低位的1;另一种是利用n & ( - n)来取出最低位的1
return n > 0 && (n & -n) == n;
return n > 0 && (n & n - 1) == 0;
要注意位运算括号的书写格式
五、位1的个数
编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。
当检查第 i 位时,我们可以让 n 与 2^i 进行与运算,当且仅当 n 的第 i 位为 1 时,运算结果不为 0。
class Solution {
public:
int hammingWeight(uint32_t n) {
int ans = 0;
for (int i = 0; i < 32; ++i){//int型共32位二进制
if (n & (1 << i)){
++ans;
}
}
return ans;
}
};
class Solution {
public:
int hammingWeight(uint32_t n) {
int ans = 0;
while (n){
n &= n - 1;//每次除去一个最低位
++ans;
}
return ans;
}
};
六、190. 颠倒二进制位
颠倒给定的 32 位无符号整数的二进制位。
class Solution {
public:
uint32_t reverseBits(uint32_t n) {
uint32_t ans = 0;
for (int i = 0; i < 32 && n > 0; ++i){
ans |= (n & 1) << (31 - i);//去除n的当前最低位,左移入ans中,实现倒序
n >>= 1;
}
return ans;
}
};
七、136. 只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/single-number
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution {
public:
int singleNumber(vector<int>& nums) {
//异或运算的性质应用
int ans = 0;
for (auto i : nums){
ans ^= i;
}
return ans;
}
};
位运算这里的题目,我认为应该熟记,相关运算的的公式和性质都很重要;