首先谈论下什么是时间复杂度,以及常见的时间复杂度类型
时间复杂度:指执行算法所需要的计算工作量;
空间复杂度:指执行这个算法所需要的内存空间;
常见的类型有七种
O(1): 常数复杂度
int n=0;
cout<<n<<endl;
O(log n): 对数复杂度
for(int i=0;i<n;i*=2)
cout<<i<<endl;
O(n):线性时间复杂度
for(int i=0;i<n;i++)
.....
O(n^2): 平方
for(int 1=0;i<n;i++)
for(int j=0;j<n;j++)
.....
O(n^3):立方
与O(n^2)类似
O(2^n) : 指数
递归,则为指数形式的时间复杂度
O(n!):阶乘
n!
Now进入递归算法(目前最常用使用递归的一种结构为树)
在写递归函数时,常常使用的模板
- 递归的终止条件 terminator
- 处理当前的逻辑层 process current logic
- 下操下一层 drill down
- 清理当前层 restore current status
由浅入深:
题目一:
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
示例 1:
输入: 2 输出: 2 解释: 有两种方法可以爬到楼顶。
- 1 阶 + 1 阶
- 2 阶
示例 2:
输入: 3 输出: 3 解释: 有三种方法可以爬到楼顶。
- 1 阶 + 1 阶 + 1 阶
- 1 阶 + 2 阶
- 2 阶 + 1 阶
解法一(递归,时间复杂度为2^n)
int climbStairs(int n)
{
if(n<=2)
return n;
return climbStairs(n-1)+climbStairs(n-2);
}
n越大时,执行时间越长,一般不采用
解法二(循环,线性时间复杂度)
int climbStairs(int n)
{
if(n==1)
return 1;
if(n==2)
return 2;
int f1=1;
int f2=2;
int allResult =0;
for(int i=2;i<n;i++)
{
allResult=f1+f2;
f1=f2;
f2=allResult;
}
return allResult;
}
题目二:
给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
例如,给出 n = 3,生成结果为:
[ “((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()” ]
核心思想:
- 先有左括号,才能有右括号
- 左括号数一定大于或者等于右括号数
void generate(vector<string>& strs,int left,int right,int n,string str)
{
//terminator
if(left==n && right==n)
{
strs.push_back(str);
return;
}
//process current logic
//drill down
if(left<n)
generate(strs,left+1,right,n,str+"(");
if(left>right)
generate(strs,left,right+1,n,str+")");
//restore current status
}
vector<string> generateParenthesis(int n) {
vector<string> strs;
generate(strs,0,0,n,"");
return strs;
}