知道算法很重要,但是就是提不提刷题的劲来,到现在也就刷过leetcode30来道题,从今天开始每天至少刷一道题。坚持。
斐波那契数列
斐波那契数列
1.斐波那契数列
题目描述:
斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
给定 N,计算 F(N)。
示例 1:输入:2
输出:1
解释:F(2) = F(1) + F(0) = 1 + 0 = 1.
递归实现:
class Solution {
public:
int fib(int N) {
if(N<=0)
return 0;
if(N<=2)
return N;
return fib(N-1)+fib(N-2);
}
};
非递归实现
class Solution {
public:
int fib(int N) {
if(N<=0)
return 0;
if(N<=2)
return 1;
int first=1;
int second=1;
int result;
for(int i=3;i<=N;++i)
{
result=first+second;
first=second;
second=result;
}
return result;
}
};
爬楼梯(leetcode 70)
题目描述:
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
示例 1:
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
- 1 阶 + 1 阶
- 2 阶
解题思路:
定义一个数组dp存储上楼梯的方法树,dp[i]表示走到第i个楼梯的方法数目。
当i1时,dp[1]=1;
当i2时,dp[2]=2;(两次都上一个台阶和一次上两个台阶)
当i3时,可以从第2个楼梯和第1个楼梯一步到达,dp[3]=dp[1]+dp[2]
当i4时,可以从第3个楼梯和第2个楼梯一步到达,dp[4]=dp[3]+dp[2]
…
可以总结出,第i个楼梯可以从第i-1个楼梯和第i-2个楼梯处一步到达。
dp[i]=dp[i-1]+dp[i-2];
代码描述:
class Solution {
public:
int climbStairs(int n) {
if(n<0)
return 0;
if(n<=2)
return n;
else{
int result;
int first=1;
int second=2;
for(int i=3;i<=n;i++)
{
result=first+second;
first=second;
second=result;
}
return result;
}
}
};
打家劫舍(leetcode 198)
题目描述:
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额
示例:
输入: [1,2,3,1]
输出: 4
解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
解题思路:
创建一个dp数组,每一步都放入当前能偷取的最大金额,即当前房屋和间隔房屋之和与上一个房屋金额相比的最大值
dp[i]=max(dp[i-2]+nums[i],dp[i-1])
代码:
class Solution {
public:
int rob(vector<int>& nums) {
int n=nums.size();
if(n==0)
return 0;
if(n==1)
return nums[0];
else if(n==2)
return max(nums[0],nums[1]);
else
{
int *dp=new int[n];
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];
}
}
};
环形街道抢劫 (leetcode 213)
题目描述:
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
示例:
输入: [2,3,2]
输出: 3
解释: 你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。
思路:
既然题目说是环形的,可以把它拆开来看成两个队列,分别是nums[0],nums[1],…,nums[n-2]和nums[1],nums[2],nums[n-1].保证最后两个相邻的房屋不能同一天被偷。
代码描述:
用两组dp实现真的很复杂,看一下代码:
class Solution {
public:
//用两组dp来实现
int rob(vector<int>& nums) {
if(nums.size()==0)
return 0;
if(nums.size()==1)
return nums[0];
if(nums.size()==2)
return max(nums[0],nums[1]);
vector<int> dp1(nums.size()-1,0);
vector<int> dp2(nums.size(),0);
dp1[0]=nums[0];dp1[1]=max(nums[0],nums[1]);
for(int i=2;i<=nums.size()-2;i++){
dp1[i]=max(nums[i]+dp1[i-2],dp1[i-1]);
}
dp2[0]=0;dp2[1]=nums[1];dp2[2]=max(nums[1],nums[2]);
for(int i=3;i<=nums.size()-1;i++){
dp2[i]=max(nums[i]+dp2[i-2],dp2[i-1]);
}
return max(dp1[nums.size()-2],dp2[nums.size()-1]);
}
};
看了其他人的答案,真的要学会创造接口:
class Solution {
public:
int rob(vector<int>& nums) {
if(nums.size()==0)
return 0;
if(nums.size()==1)
return nums[0];
return max(