1.char型数组初始化的时候,大小不能是变量,{0},表示每一个都初始化为’\0’
char a[100][100]={0};`
2.要退出多层循环,设置标志,内层循环退出,同样的标志,外层循环继续退出
int flag=0;
while(1)
{
while(1)
{
if(flag==1)
break;
}
if(flag==1)
break;
}
3.字符串与数字之间的转换
int a=10;
to_string(a);
string str="123";
int ret_32=atoi(str);//转换成int32
long long ret_64=atoll(str);//转换成int64
4.指数运算
pow(2,31);//2的31次方
5.正则表达式匹配
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。
‘.’ 匹配任意单个字符
‘*’ 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
示例 1:
输入:s = “aa” p = “a”
输出:false
解释:“a” 无法匹配 “aa” 整个字符串。
示例 2:
输入:s = “aa” p = “a*”
输出:true
解释:因为 ‘*’ 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 ‘a’。因此,字符串 “aa” 可被视为 ‘a’ 重复了一次。
示例 3:
输入:s = “ab” p = “."
输出:true
解释:".” 表示可匹配零个或多个(’*’)任意字符(’.’)。
示例 4:
输入:s = “aab” p = “cab”
输出:true
解释:因为 ‘*’ 表示零个或多个,这里 ‘c’ 为 0 个, ‘a’ 被重复一次。因此可以匹配字符串 “aab”。
示例 5:
输入:s = “mississippi” p = “misisp*.”
输出:false
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/regular-expression-matching
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
bool isMatch(string s, string p) {
regex reg(p);
bool ret=regex_match(s,reg);
return ret;
}
6.unordered_map 初始化
unordered_map<char,int> map={
{'I',1},
{'V',5},
{'X',10},
{'L',50},
{'C',100},
{'D',500},
{'M',1000}
};
7.双指针常用
一前一后,满足什么规则,移动什么指针
(1)找寻和大小,排序后,左指针从左到右,右指针从右到左,
for(int i=0;i<nums.size();i++)
{
int left=i;
int right=nums.size()-1;
while(left<right)
{
sum=nums[left]+nums[right];
if(sum<target)
left++;
else if(sum>target)
right--;
else
return result;
}
}
8.回溯算法
(1)回溯算法基本模板
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
9.sort的比较函数需要static
static bool cmp(int node1,int node2)
{
return node1<node2;
}
sort(vec.begin(),vec.end(),cmp);
10.重构链表的时候,最后一个链表节点一定要记得手动指向nullptr
需要注意的点,重新连接链表的时候,一定要把最后一个链表位置的next置为空指针,因为一般最后一个节点的下一个指针不是nullptr,容易形成循环链表,所以这一点一定要注意
11.reverse(vec.begin(),vec.end())
注意reverse第一个参数是开始节点,第二个参数是截至节点的下一个节点。
reverse(vec.begin()+i,vec.begin()+i+k);
12.去重
vector<int>::iterator new_end;
new_end=unique(nums.begin(),nums.end());
nums.erase(new_end,nums.end());
nums处理后变成了去重后的数组
13.回溯全排列
无重复元素
vector<vector<string>> result;
vector<string> path;
void BackTracking(vector<string>& words,vector<bool>& used)
{
if(path.size()==words.size())
{
result.push_back(path);
return;
}
for(int i=0;i<words.size();i++)
{
if(used[i])
continue;
path.push_back(words[i]);
used[i]=true;
BackTracking(words,used);
path.pop_back();
used[i]=false;
}
}
有重复元素
class Solution {
vector<vector<int>> result;
vector<int> path;
void BackTracking(vector<int>& nums,vector<bool>& used)
{
if(path.size()==nums.size())
{
result.push_back(path);
return;
}
for(int i=0;i<nums.size();i++)
{
if(used[i]==true)
continue;
if(i>0&&nums[i]==nums[i-1]&&used[i-1]==false)
{
continue;
}
path.push_back(nums[i]);
used[i]=true;
BackTracking(nums,used);
path.pop_back();
used[i]=false;
}
}
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
sort(nums.begin(),nums.end());
vector<bool> used(nums.size(),false);
BackTracking(nums,used);
return result;
}
};
14.回溯组合
无重复元素,不能使用重复的
vector<vector<int>> result; // 存放符合条件结果的集合
vector<int> path; // 用来存放符合条件结果
void backtracking(int n, int k, int startIndex) {
if (path.size() == k) {
result.push_back(path);
return;
}
for (int i = startIndex; i <= n; i++) {
path.push_back(i); // 处理节点
backtracking(n, k, i + 1); // 递归
path.pop_back(); // 回溯,撤销处理的节点
}
}
无重复元素,可以使用重复的
vector<vector<int>> result;
vector<int> path;
int sum=0;
void BackTracking(vector<int>& candidates,int target,int start_index)
{
if(sum>=target)
{
if(sum==target)
result.push_back(path);
return;
}
for(int i=start_index;i<candidates.size();i++)
{
path.push_back(candidates[i]);
sum+=candidates[i];
BackTracking(candidates,target,i);//不是i+1了
path.pop_back();
sum-=candidates[i];
}
}
有重复元素,不能使用重复的
class Solution {
private:
vector<vector<int>> result;
vector<int> path;
void BackTracking(vector<int>& candidates, int target,int sum,int start_index,vector<bool>& used)
{
if(sum>=target)
{
if(sum==target)
result.push_back(path);
return;
}
for(int i=start_index;i<candidates.size();i++)
{
if(i>0&&candidates[i]==candidates[i-1]&&used[i-1]==false)
continue;
path.push_back(candidates[i]);
sum+=candidates[i];
used[i]=true;
BackTracking(candidates,target,sum,i+1,used);
path.pop_back();
sum-=candidates[i];
used[i]=false;
}
}
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(),candidates.end());
vector<bool> used(candidates.size(),false);
BackTracking(candidates,target,0,0,used);
return result;
}
};
排列组合的总结:组合和排列的区别,组合有start_index,排列每次是从0开始,然后使用used数组来判断有没有使用过,实现排列。
是否有重复元素:有重复元素,就涉及到去重。首先必须先对原数组进行排序,然后使用used数组,if(i>0&&candidates[i]==candidates[i-1]&&used[i-1]==false) continue;
用这个实现一层去重,上下层可以使用。然后再结合if(used[i]==true) continue;
实现排列还是组合。
无重复元素,是否可以重复使用元素实现组合,在于回溯的start_index
是i+1,还是i。i+1不能重复使用,i可以重复使用
15.匹配字符串,存入匹配成功的文本串的开始下标
vector<int> ret;
void pipei(string s,string a)
{
for(int i=0;i<s.size();i++)
{
int index;
if(s[i]==a[0])
{
index=i;
int j;
for(j=0;j<a.size();j++)
{
if(s[i]==a[j])
{
i++;
}
else
{
break;
}
}
if(j==a.size())
{
ret.push_back(index);
}
i=index;
}
}
}
16.unordered_map<string,vector<string>> mp
这样可以按照一定规则对字符串组分类
用key来存储规则,用值来存储分类结果
mp[key].push_back(strs[i]);
可直接实现分类,存在key就添加,不存在就新建新的类
vector<vector<string>> result;
for(auto it=mp.begin();it!=mp.end();it++)
{
result.push_back(it->second);
}
最后通过上面这样把分好类的结果提取出来
17.字符串分割函数(简单易写版本)
vector<string> split(string &path,char flag)
{
vector<string> result;
string cur;
for(char a:path)
{
if(a==flag)
{
result.push_back(cur);
cur.clear();
}
else
{
cur+=a;
}
}
result.push_back(cur);
return result;
}
18.链表去重
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(head==nullptr)
return head;
ListNode* cur=head;
while(cur->next!=nullptr)
{
if(cur->val==cur->next->val)
{
int x=cur->val;
while(cur->next&&cur->next->val==x)
{
cur->next=cur->next->next;
}
}
else
{
cur=cur->next;
}
}
return head;
}
};
链表删除有重复的元素
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(head==nullptr)
{
return nullptr;
}
ListNode* vir_head=new ListNode(0,head);
ListNode* cur=vir_head;
while(cur->next&&cur->next->next)
{
if(cur->next->val==cur->next->next->val)
{
int x=cur->next->val;
while(cur->next&&cur->next->val==x)
{
cur->next=cur->next->next;
}
}
else
{
cur=cur->next;
}
}
return vir_head->next;
}
};
总结:如果头节点可能被删除,就增加虚拟头节点。
然后设置cur节点从头节点或者虚拟头节点开始
先判断cur节点可能涉及到的最后一个节点的有效性,例如cur->next,cur->next->next,然后进行删除操作,cur->next=cur->next->next
最后返回头节点或者虚拟头节点的下一个节点
19.二叉树
定义+中序遍历
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
vector<int> result;
public:
vector<int> inorderTraversal(TreeNode* root) {
if(root==nullptr)
{
return result;
}
inorderTraversal(root->left);
result.push_back(root->val);
inorderTraversal(root->right);
return result;
}
};
二叉搜索树:二叉查找树 (Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的 二叉树 : 若它的左子树不空,则左子树上所有结点的值均小于它的 根结点 的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为 二叉排序树 。. 二叉搜索树作为一种经典的数据结构,它既有链表的快速插入与删除操作的特点,又有数组快速查找的优势;所以应用十分广泛,例如在文件系统和数据库系统一般会采用这种数据结构进行高效率的排序与检索操作。
二叉搜索树的中序遍历是升序序列,如果中序遍历不是升序序列,就不是二叉搜索树
二叉树重构套路
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
private:
unordered_map<int,int> index;
TreeNode* my_build(vector<int>& preorder, vector<int>& inorder,int pre_left,int pre_right,int in_left,int in_right)
{
if(pre_left>pre_right)
return nullptr;
int pre_root=pre_left;
int in_root=index[preorder[pre_root]];
TreeNode* root=new TreeNode(preorder[pre_root]);
int size_left=in_root-in_left;
root->left=my_build(preorder, inorder, pre_root+1,pre_root+size_left,in_left,in_root-1);
root->right=my_build(preorder, inorder, pre_root+size_left+1,pre_right,in_root+1,in_right);
return root;
}
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
for(int i=0;i<inorder.size();i++)
{
index[inorder[i]]=i;
}
return my_build(preorder,inorder,0,preorder.size()-1,0,inorder.size()-1);
}
};
计算二叉数的高度
int height(TreeNode* root)
{
if(root==nullptr)
return 0;
else
{
return max(height(root->left),height(root->right))+1;
}
}
20.求一个数组中的最大值
return *max_element(dp_max.begin(),dp_max.end());
21.深度优先遍历(DFS)
红与黑
/*【题目描述】
有一间长方形的房子,地上铺了红色、黑色两种颜色的正方形瓷砖。你站在其中一块黑色的瓷砖上,只能向相邻的黑色瓷砖移动。请写一个程序,计算你总共能够到达多少块黑色的瓷砖。
【输入】
包括多个数据集合。每个数据集合的第一行是两个整数W和H,分别表示x方向和y方向瓷砖的数量。W和H都不超过20。在接下来的H行中,每行包括W个字符。每个字符表示一块瓷砖的颜色,规则如下 :
1)‘.’:黑色的瓷砖;
2)‘#’:白色的瓷砖;
3)‘@’:黑色的瓷砖,并且你站在这块瓷砖上。该字符在每个数据集合中唯一出现一次。
当在一行中读入的是两个零时,表示输入结束。
【输出】
对每个数据集合,分别输出一行,显示你从初始位置出发能到达的瓷砖数(记数时包括初始位置的瓷砖)。
【输入样例】
6 9
....#.
.....#
......
......
......
......
......
#@...#
.#..#.
0 0
【输出样例】
45
————————————————
版权声明:本文为CSDN博主「Alex_McAvoy」的原创文章,遵循CC 4.0 BY - SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https ://blog.csdn.net/u011815404/article/details/80282632
*/
//#include<iostream>
//#include<cstdio>
//#include<cstdlib>
//#include<cstring>
//#define N 1001
//using namespace std;
//int m, n;
//char ch;
//int maps[N][N];
//int vis[N][N];
//int dir[4][2] = { {0,1},{0,-1},{1,0},{-1,0} };
//int cnt;
//void dfs(int x, int y)
//{
// for (int i = 0; i < 4; i++)
// {
// int nx = x + dir[i][0];
// int ny = y + dir[i][1];
// if (nx >= 1 && ny >= 1 && nx <= n && ny <= m && vis[nx][ny] == 0 && maps[nx][ny] == 1)
// {
// vis[nx][ny] = 1;
// cnt++;
// dfs(nx, ny);
// }
// }
//}
//int main()
//{
// while (cin>>m>>n && m && n)
// {
// int x, y;
// cnt = 1;
// memset(vis, 0, sizeof(vis));
// memset(maps, 0, sizeof(maps));
//
// for (int i = 1; i <= n; i++)
// for (int j = 1; j <= m; j++)
// {
// cin >> ch;
// if (ch == '@')
// {
// x = i;
// y = j;
// maps[i][j] = 1;
// }
// if (ch == '.')
// maps[i][j] = 1;
// if (ch == '#')
// maps[i][j] = 0;
// }
// vis[x][y] = 1;
// dfs(x, y);
// cout << cnt << endl;
// }
// return 0;
//}
#include <iostream>
#include <vector>
using namespace std;
vector<vector<int>> around = { {0,-1},{0,1},{1,0},{-1,0} };
void dfs( int& x, int& y, vector<vector<int>>& my_vec, int& n, int& m,vector<vector<bool>>& used, int& cnt)
{
for (int i = 0; i < 4; i++)
{
int nx = x + around[i][0];
int ny = y + around[i][1];
if (nx >= 0 && ny >= 0 && nx < n && ny < m )
{
if (used[nx][ny] == 0 && my_vec[nx][ny] == 1)
{
cnt++;
used[nx][ny] = 1;
dfs(nx, ny, my_vec, n, m, used, cnt);
}
}
}
}
int main()
{
int m, n;
while (cin >> m >> n &&m != 0 && n != 0)
{
vector<vector<int>> my_vec(n,vector<int>(m,0));
vector<vector<bool>> used(n,vector<bool>(m,0));
int cnt = 1;
int x = 0, y = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
char temp;
cin >> temp;
if (temp == '@')
{
x = i;
y = j;
my_vec[i][j] = 1;
used[x][y] = 1;
}
else if (temp == '.')
{
my_vec[i][j] = 1;
}
else
{
my_vec[i][j] = 0;
}
}
}
dfs(x, y, my_vec, n, m, used, cnt);
cout << cnt << endl;
}
return 0;
}