参考《代码随想录》《hello, 算法》学习笔记
ACM模式处理:
1. 处理字符串输入
cin: 通过空白(空格、制表符、换行符)来确定字符串的结束位置,即cin在获取字符数组输入时只读取一个单词
getline():读取一整行,通过回车键输入的换行符来确定输入结尾,或者cin.getline().
cin.getline(name, size) 读取19个字符或者遇到换行符停止读取
getline(cin, str):读取输入的一行字符串
get():与getline()类似,但是会将换行符留在队列中,第二次调用get()时遇到这个保留的换行符认为输入到达末尾。处理这个换行符可以加一句没有参数的get()
- 以逗号分隔字符串
- 如string="asm,asd,grb",处理后得到 res[3]={asm, asd, grb};
vector<string> get_str(string &s){
vector<string>res;
string t;
for(int i=0;i<s.size();i++){
if(s[i]==','){
res.push_back(t);
t.clear();
}
else{
t.push_back(s[i]);
}
}
res.push_back(t);//最后一个字符没有逗号,手动加入
return res;
}
- 以空格分隔字符串
istringstream()
string str = "this is a test";
istringstream iss(str);
string word;
vector<string> words;
while (iss >> word) {
words.push_back(word);
}
通用方法分割字符串(以单个字符分割)
string origin_str = "hello world !"; // 需要进行分割的字符串
//或者可以输入
//string origin_str;
//cin >> origin_str;
stringstream ss(origin_str); // 使用字符串构造一个stringstream类型(流)数据
char c = ' '; // 设定好分隔符号(只能使用一个字符进行分割)
vector<string> results; // 用来存储结果
string str; //用来接收每个分割的字符串
// 开始分隔
while (getline(ss, str, c)) {
results.push_back(str);
}
1、数据结构:
1.数组
总结图:
内存分配
字节对齐
2.二叉树
- 二叉平衡树:任意一个节点的左子树和右子树高度之差小于等于1
- 完全二叉树:除了叶子节点这一层,每个节点都有两个子节点,且最后一层的节点靠左排列
- 二叉搜索树:节点左边的节点值比该节点值小,右边节点值比该节点值大,中序遍历有序
- 平衡二叉搜索树:二叉搜索树和平衡二叉树的结合
对于构建二叉树,必须存在中序遍历(有中序遍历才能分隔左右子树)
根据前序遍历和中序遍历构建二叉树:
2、算法
1.回溯算法:
优点:本质上是DFS,能够找到所有可能的解决方案,在合理剪枝操作下,效率可以达到很高
局限性:不适用于大规模或者复杂问题,时间复杂度和空间复杂度很高
优化:1.剪枝,避免搜索不必要的路径 2.启发式搜索,引入估计值,优先搜索最可能的有效路径
代码框架:
void backtrack( ){
//1.判断是否有解
if(issolution){
record();//有解记录
//找到解不继续搜索
return;
}
//没找到解,遍历所有选择求解
for( ){
//剪枝,并判断路径是否合法
if( ){
//更新状态
makechoice();
//递归
backtrack();
///回退
undochoice();
}
}
}
应用:
1、全排列
给定数组,算出数组所有排列方式
- 无相等元素
所有元素是被唯一选择,可以用vector<bool>states标记每个元素的状态
时间复杂度:O(n!)
- 有相等元素
在同一轮选择中,相等的元素可以重复选择,但是在下一轮中不能再选择相等的元素
剪枝操作:如果choice[i]==choice[i-1],则跳过这次选择
2、子集和
给定数组,找出所有的集合(集合中元素之和为target),元素可以重复选择
- 无重复元素
由于元素可以重复选取,不适合用bool数组来标记状态,但需要对重复子集剪枝,如集合{4,5}和集合{5,4}
剪枝操作:当前选择为s[i],下一轮选择从i开始往后选择
- 有相等元素
给定数组,找出所有的组合,使得组合元素之和为target,可能包含重复元素,每个元素只能选择一次
只选择一次时需要标记元素选择情况:bool数组
剪枝操作:避免在同一轮选择中选择相等的元素,先将数组排序,使得相等的元素相邻
要点一:s[i]==s[i-1]时跳过本次选择
要点二:下一轮选择,从i+1开始
3、N皇后
给定n个皇后和一个nxn大小的棋盘,皇后可以攻击同一行、同一列以及同一斜线方向的棋子,要求两两皇后不能相互攻击
题解:逐行放置(在回溯函数中行参数为row+1即可)皇后,对列和对角线进行约束,记录每一列以及对角线是否有皇后
要点:同一主对角线:row-col 为恒定值,同一次对角线: row+col 为恒定值
注意:row-col 取值范围为 [-n+1, n-1] row+col取值范围为[0-2n-2],因此对于标记主对角线的布尔数组diag1索引会出现负数,统一加上n-1
2. 动态规划
记忆化搜索:从顶至底,从原问题开始,将大问题分解为小问题,并采取数组记录重复子问题,因此常用递归来实现。
动态规划:从底至于顶,从小问题开始,构建大问题的解,因此使用循环迭代实现
动态规划解题关键:寻找递推公式,即状态转移方程
无后效性:给定一个确定的状态,他的未来发展只与当前的状态有关,而与过去经历的所有状态无关
应用:最优化问题
1. 最优子结构
原问题的最优解是从子问题的最优解构建得来的
第n阶最大方案数量等于第n-1阶和第n-2阶最大方案数量之和