算法题
数字字符串转换为字母字符串
题目描述:有一个字符串,里面字符全部是数字,当一个字符或者相邻字符组合,大小在1-26之间,就认为可以替换成字母,比如说1可以替换成A,26可以替换成Z,0不可以替换,返回0;但是10,20都是正确的。计算出字符串有多少种转换结果。
方法1:递归。dp[i]表示以str[i-1]为结尾,转换结果数,那么
如果str[i-1]不为0,那么
dp[i] += dp[i-1]
如果str[i-2]!=0 and stoi(str(i-2,i-1))在1-26范围内,
dp[i] += dp[i-2]
int helper(string s) {
int n = s.size();
vector<int> dp(n+1,0);
if (n == 0)
return 0;
if (n == 1)
return s[0] == '0' ? 0 : 1;
if (s[0] == '0')
return 0;
dp[0] = 1;
dp[1] = 1;
for (int i = 2; i <= n; i++) {
if (s[i-1] != '0')
dp[i] += dp[i-1];
int t = stoi(s.substr(i-2,2));
if (s[i-2]!='0' && t >= 10 && t <= 26){
dp[i] += dp[i-2];
}
}
return dp[n];
}
方法2:类似斐波那契数列,但是是从后向前递归,O(N),可以不用开辟vector空间,直接用两个变量代替,这样空间复杂度只有O(1).
这里虽然是斐波那契数列,但是这里有条件,并不是严格的斐波那契,所以不能用矩阵乘法。
todo
跳跃游戏
题目描述:一个数组arr,arr[i] = k表示在i位置可以跳跃1~k个距离,问题是从位置0出发,最少几步可以到最后?
方法1:新建一个同样大小的数组p,p[i]表示到达i出最小步数,那么p[i]的值是第一次到达i处的值,比如说,arr[3,1,2,2],那么从0开始跳跃,p[1] = 1,p[2] = 1,p[3] = 1;arr[1] = 1,这时候从位置1也可以到达位置2,但是这时候p[2]还是等于1.
int helper(vector<int> &nums) {
int n = nums.size();
vector<int> p(n,0);
for (int i = 0; i < n - 1; i++) {
int t = nums[i];
for (int j = 1; j <= t; j++) {
if (p[i+j] == 0)
p[i+j] = p[i] + 1;
}
}
return p[n-1];
}
但是这个代码时间复杂度为O(N^2),空间复杂度为O(N).
方法2:时间复杂度为O(N),空间复杂度O(1).
todo
数组中最长连续序列
题目描述:给了一个数组,[100,2,1,200,3,4],找出最长数组[1,2,3,4]的个数。
N皇后问题
设计模式
适配器模式
Adapter模式
什么时候用?客户端希望类具有某一个接口,但是没有,所以需要一个适配器类提供这个接口。将接口替换成需要的接口。
分为类的适配器模式和对象的适配器模式。
类适配器是创建一个adapter类继承target和adaptee类,衔接起来target中的request函数。
对象适配器是在adapter中多了一个adaptee对象。
备忘录模式
类需要保存之前状态,并且能够恢复状态。
有一个备忘录类Mement保存状态,Caretaker类用来保存备忘录,Originator类用来创建备忘录,可以保存和恢复原来状态。
组合模式Composite
又叫部分整体模式。组合模式用于将多个对象组合成树形结构,以表示整体-部分关系。
例子:文件和文件夹目录。有一个component抽象类,提供了文件和文件夹共同的属性和行为,然后composite类继承了component,会有容器存储文件,实现了文件夹行为,leaf类也继承了component,但是少了一些文件夹行为。
组合模式
迭代器模式
提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。
迭代器模式
单例模式
就是一个类只能创建一个对象。面试高频题目。用静态内部类实现。
桥接模式
一个类有多个维度变化会影响行为。
Bridge模式有时候类似于多继承方案,但是多继承方案往往违背了类的单一职责原则(即一个类只有一个变化的原因),复用性比较差。Bridge模式是比多继承方案更好的解决方法。
Bridge模式的应用一般在“两个非常强的变化维度”,有时候即使有两个变化的维度,但是某个方向的变化维度并不剧烈——换言之两个变化不会导致纵横交错的结果,并不一定要使用Bridge模式。