C++头文件
//c++头文件
#include<iostream>
#include <algorithm>
using namespace std;
Vector类型
//头文件
#include <vector>
//vector类型
vector<int> v1;
vector<vector<int> > v2; //注意空格,相当于二维数组int a[n][n];
vector<int> v3 = {1,2,3,4,5}; //列表初始化,注意使用的是花括号
vector<int> v5(5,-1); //初始化为-1,-1,-1,-1,-1,数目+初始化的值
vector<int> v7(10); //默认初始化为10个0,先开辟固定空间,很重要!!!
vector<vector<int>> v8(3,vector<int>(3,0)); //定义v8[3][3]初始化
//vector的各种操作
v5.front(); //访问第一个元素
v5.back(); //访问最后一个元素
v5.pop_back(); //删除最后一个元素
v5.push_back(6); //加入一个元素并把它放在最后
v5.clear(); //清除所有内容
v5.empty(); //判断vector是否为空
v5.size(); //给出vector的大小
v5.insert(v5.begin()+1,9); //在第二个位置插入新元素9
v5.erase(v5.begin()+3); //删除第四个元素
Stack类型
//头文件
#include<stack>
//stack类型
整型(int) stack<int> s
浮点型(float、double) stack<float> q stack<double> s
字符型(char) stack<char> s
字符串型(string) stack<string> s
指针类型(ListNode*) stack<ListNode*> s
二元结构体类型(pair) stack<pair<int,int>> s
//相关栈的操作
s.empty(); 如果栈为空返回true,否则返回false
s.size(); 返回栈中元素的个数
s.pop(); 删除栈顶元素
s.top(); 返回栈顶的元素,但不删除
s.top()=a; 修改栈顶元素
s.push(val); 在栈顶压入新元素val
Queue类型
//头文件
#include <queue>
//queue类型
queue<int> q;
queue<ListNode*> q;
//queue的各种操作
q.push(); //从队尾入队
q.pop(); //从队头出队
q.front(); //返回队头元素
q.back(); //返回队尾元素
q.size(); //返回队长度
q.empty(); //判断是否队空
Set类型
//头文件
#include <set>
//定义set类型
set<int> s1 = {9,8,,5,6,7,7 }; //自动排序,从小到大,剔除相同项
set<string> s2 = { "hello" }; //字典序排序
unordered_set<int> s3; //不会排序的,但是会剔除相同项
//set的相关函数使用
s1.insert(9); //有这个值了,do nothing
s2.insert("aaa"); //没有这个字符串,添加并且排序
s1.find(9); //寻找元素:不存在会返回s1.end(),个人觉得很难用!!
s1.count(9); //看元素存在不存在会返回1/0,个人觉得好用!!!
//set的适用场景
set缺点:必须使用迭代器遍历 无法随机存取
set优点:如果题目要求元素唯一可以用set
String类型
//头文件
#include <string>
//string类型
string s1; //初始化字符串,空字符串
string s3 = "I am"; //直接初始化,s3存了字符串
string s4(10, 'a'); //s4存的字符串是aaaaaaaaaa
//string的各种操作
string s8 = s3 + s4; //将两个字符串合并成一个
s8.size(); //字符串的大小
s8.empty(); //判断字符串为空返回true,否则返回false
cout<<stoi(ss); //字符串转int
if(s[i]>='a'&&s[i]<='z') //判断是否为小写字母
if(s[i]>='A'&&s[i]<='Z') //判断是否为大写字母
if(s[i]>='0'&&s[i]<='9') //判断是否为数字
s[0]-'0'; //如果为数字字符可以通过此法获取数字
s8.push_back('a'); //string也可以push_back
string str=s.substr(开始,长度); //获取子串
堆元素类型
//头文件
#include<algorithm.h>
//堆元素操作
vector<int> v1={10,30,22,6,15,9}; //建立在vector的基础上
make_heap(v1.begin(), v1.end()); //默认创建大顶堆(从小到大)
make_heap(v1.begin(), v1.end(), greater<int>()); //创建小顶堆(从大到小)
v1.push_back(4);
push_heap(v1.begin(), v1.end()); //push_heap插入数据恢复成堆
push_heap(v1.begin(), v1.end(), greater<int>());
pop_heap(v1.begin(), v1.end()); //pop_heap堆顶元素放到末尾
pop_heap(v1.begin(), v1.end(), greater<int>());
v1.pop_back(); //删除堆顶元素
sort_heap(v1.begin(), v1.end()); //大顶堆进行从小到大堆排序
sort_heap(v1.begin(), v1.end(), greater<int>()); //小顶堆进行从大到小堆排序
Map类型
//头文件
#include <map>
//map数据的访问
map<string,int> m; //默认有序map,参数key+value(key是唯一的)
unordered_map<int,int> m1; //无序map,不会自动排序
m["Kobe"] = 100; //给key赋予value
//map的相关函数
m.size(); //返回map中元素的个数
m.erase("Kobe"); //通过关键字来删除键值对
m.clear(); //清空map全部键值对
m.count(k); //返回键K用于查看存不存在1/0,非访问value操作
m.find(9); //寻找元素:不存在会返回m.end(),个人觉得很难用!!
if(m1 == m2) //两个map之间可以之间比较
m.insert(pair<string,int>("Mary",89)); //通过insert函数来实现增加元素
m["不存在的键"]++; //会自动添加不存在的键,并且值初始化为0,再加加变为1
//map的遍历操作
for(map<int, int>::iterator it = m.begin();it!=m.end();it++){
cout << it->first << " " << it->second << endl;
}
Pair类型
//头文件
#include<utility>
//pair类型(二元结构体)
带初始值的 pair<string, int> p={"wangyaqi",1};
不带初始值的 pair<string, int> p;
结构体数组 pair<int,int> p[20];
//访问数据
p[i].first 代表第一个元素
p[i].secondsecond 代表第二个元素
st.push({1,1}); 往栈压pair类型
输入输出操作
//读取一行字符串
string str;
cin>>str; //遇到空格或者回车键即停止
getline(cin, str); //获取一整行包括空格遇到回车停止
//输入包含多组测试数据,每组数据占一行,多少组未知
string s;
while(cin>>s){
//处理s的操作
}
常用STL自带算法
//排序算法
sort(v1.begin(), v1.end()); //从小到大排序
sort(v1.begin(), v1.end(), greater<int>()); //从大到小排序
动态规划的三个解题步骤是:
(1)定义子问题f(n): 规模缩小 原问题要能由子问题表示 确定dp数组以及下标的含义
(2)写出子问题的递推关系: 重点思考和f(n-1)和f(n-2)的递推关系 dp数组如何初始化
(3)确定DP计算顺序: 最好使用自底向上的DP数组的循环方法 子问题数组 找到依赖关系
动态规划常见问题
1、动归基础
2、背包问题
子问题:dp[i][j]表示取下标物品0-i 背包容量为j的最大价值
(1)0-1背包
递推关系:dp[i][j]=(dp[i-1][j],dp[i-1][j-weight[i]]+price[i])
vector<vector<int>> dp(thingNum,vector<int>(bagSize+1,0));
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + price[i]);
(2)完全背包
dp[i][j] = dp[i-1][j]; //不放i,初始化dp[i][j]
for (int k = 1; j - k * weight[i] >= 0;k++){ //下面是放多个i物品
dp[i][j] = max(dp[i][j],dp[i-1][j-k*weight[i]] + k*price[i]);
}
3、打家劫舍
子问题:在偷下标为k间房的基础上,偷到的最大金额
递推关系:dp[k]=max(dp[0]-dp[k-2])+nums[k];
4、子序列问题
(1)子问题:dp[i]找到以下标i结尾的最长递增子序列
递推关系:dp[i]=dp[i-1]+1(条件:nums[i-1]<nums[i]) 否则dp[i]=1;
(2)子问题:以i结尾的乘积最大非空连续子数组
递推关系:dpMax[i]=max(dpMax[i-1]*nums[i],dpMin[i-1]*nums[i]);
递推关系:dpMin[i]=min(dpMax[i-1]*nums[i],dpMin[i-1]*nums[i]);
5、完全平方数
子问题:和为k的完全平方数的最少数量
递推关系:dp[k]=min(1+dp[k-j*j]) j从(1-根号k)循环
回溯要考虑的以下的点:
1、需要回头找用:vector<bool> used(n,false);
2、不能回头找用:int startIndex = 0;
3、多个数组使用:int index = 0;
3、在递归树上的收集情况:收集所有结点||收集叶子结点
4、判断递归结束的条件:什么时候叶节点可以终止
5、进行遍历用循环还是条件判断:数组元素少用条件判断,元素多用循环
//常用全局变量
vector<int> path; //目前的路径的结果
vector<vector<int> > ans; //返回的回溯的答案
vector<bool> used(n,false); //选择过不能再次被选择用used记录元素访问情况
backtreaking(nums,used,0);
//回溯算法本身
void backtreaking(vector<int> nums,vector<bool> used,int startIndex,int index){
//收获所有结果,进入一个递归就会收获结果
ans.push_back(path);
//if先处理终止条件
if(终止条件){
//收集结果,叶子结点
ans.push_back(path);
return;
}
//遍历集合元素,如果遍历集合中只有两个元素(),那么就直接用if不用循环了,直接判断各种情况
if(left==right && left<n)
if(left>right && left<n)
for(int i=0/startIndex;i<nums[index].size();i++){
//处理结点,选择未访问结点加入路径
if(used[i]==true) continue;
used[i]=true;
path.push_back(nums[i]);
path.push_back(nums[index][i]);
//递归函数
backTreaking(nums,used); //从头访问数组中不重复的元素
backTracking(nums,i+1); //访问数组的下一个元素
backTracking(nums,index+1); //访问下一个数组
//回溯操作:对于path的修改
path.pop_back();
used[i]=false; //used的处理
sum=sum-nums[i]; //出递归条件的处理
}
return;
}
//网格dfs模板
void dfs(vector<vector<char> >& grid, int row, int line) {
//行列在范围内
if (0<=row && row<grid.size() && 0<=line && line<grid[0].size()){
//访问格子
grid[row][line] = '2';
dfs(grid, row - 1, line);//上
dfs(grid, row + 1, line);//下
dfs(grid, row, line - 1);//左
dfs(grid, row, line + 1);//右
}
return;
}
//采用BFS可以用来求最短路径问题
int orangesRotting(vector<vector<int>>& grid) {
int m = grid.size();
int n = grid[0].size();
queue<pair<int, int>> q;
int count = 0;
int newC = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] == 2) {
q.push({ i,j });
}
else if (grid[i][j] == 1) {
newC++;
}
}
}
if (newC == 0) return 0;
while (!q.empty() && newC > 0) {
int k = q.size();
for (int i = 0; i < k; i++) {
//出栈
pair<int, int> p = q.front();
q.pop();
int x = p.first;
int y = p.second;
if (grid[x][y] == 1) {
grid[x][y] = 2;
newC--;
}
//上下左右入栈
if (x - 1 >= 0 && grid[x - 1][y] == 1) q.push({ x - 1,y });
if (x + 1 < m && grid[x + 1][y] == 1) q.push({ x + 1,y });
if (y - 1 >= 0 && grid[x][y - 1] == 1) q.push({ x,y - 1 });
if (y + 1 < n && grid[x][y + 1] == 1) q.push({ x,y + 1 });
}
count++;
}
if (newC == 0) {
return count - 1;
}
else {
return -1;
}
}
零星知识点
1、判断一个数要在一个范围内要写成两个条件,比如:0<=row && row<grid.size()
2、unordered_map<int,int> m;
m.insert(pair<int,int>(nums[i],i));
m.count(target-nums[i])>0
map<string,vector<string>> m;
3、map的遍历
for (map<int,int>::iterator it = m.begin(); it != m.end(); it++) {
cout << it->first << it->second;
}
4、int num1 = 123;
string s = to_string(num1); //数字转字符串
int num2 = stoi(s); //字符串转数字
int num3 = '9'-'0'; //字符转数字
(int)s[i] //字符转数字的ask码
char c = (char)9; //数字转字符
5、printf("%.3f\n", c); //double类型保留三位小数
6、sort(v.begin(),v.end(),cmp);
bool cmp(pair<double, double> a, pair<double, double> b){
return a.second / a.first < b.second / b.first; //单价低的优先
}
7、润年:(year%4==0&&year%100!=0)||(year%400==0) 二月29天
8、日期问题:月份天数直接打表写成数组
9、最大公约
int gcd(int a,int b) {
if (b == 0) return a;
return gcd(b,a%b);
}
10、最小公倍
int lcm(int a,int b) {
int temp=gcd(a,b);
return a*b/temp;
}
11、异或运算: 针对二进制同0异1 针对十进制偶数个消掉奇数个留下 找奇数个数用
使用:ans=5^4^5; //ans=4
12、二分查找: 有可能找不到就<= 肯定能找到就< 适用于找数要求时间复杂度为O(logn)
13、快慢指针:
(1)当题目中要求只遍历一遍链表,就应该想到快慢指针,一般只需要定义两个变量即可
(2)把数组看成链表,运用快慢指针
14、递归思路: 递归函数是什么意思 边界条件是什么 相同步骤是什么
15、排版类问题
(1)一共有几行
(2)每行长度怎么变化
(3)每行什么时候开始打印
线性表衍生题目(初试)
class Solution {
public:
ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
ListNode *l1=headA,*l2=headB,*retA=headA,*retB=headB;
vector<int> conA,conB;
int count=0;
while(l1!=NULL){
conA.push_back(l1->val);
l1=l1->next;
}
while(l2!=NULL){
conB.push_back(l2->val);
l2=l2->next;
}
for(int i=conA.size()-1,j=conB.size()-1;i>=0&&j>=0;i--,j--){
if(conA[i]==conB[j]){
count++;
}else{
if(i==conA.size()-1){
return NULL;
}
break;
}
}
for(int i=0;i<conA.size()-count;i++){
retA=retA->next;
}
for(int i=0;i<conB.size()-count;i++){
retB=retB->next;
}
while((&*retA)!=(&*retB)){
retA=retA->next;
retB=retB->next;
}
return retA;
}
};
//反转链表
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* ret=NULL,*temp=head;
while(head!=NULL){
head=head->next;
temp->next=ret;
ret=temp;
temp=head;
}
return ret;
}
};
class Solution {
public:
bool isPalindrome(ListNode* head) {
vector<int> num;
ListNode* list=head;
while(head!=NULL){
num.push_back(head->val);
head=head->next;
}
for(int i=0;i<num.size();i++){
if(num[i]==num[num.size()-1-i]){
;
}else{
return false;
}
}
return true;
}
};
class Solution {
public:
bool hasCycle(ListNode *head) {
unordered_set<ListNode*> num;
ListNode* temp=head;
int count=0;
while(head!=NULL){
count++;
head=head->next;
num.insert(temp);
if(count!=num.size()){
return true;
}
temp=head;
}
return false;
}
};
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
unordered_set<ListNode*> s; //ListNode结点的地址
ListNode* temp=head;
int len=0;
int isUse=0;
while(temp!=NULL){
s.insert(temp);
len++;
if(s.size()!=len){
len--;
isUse=1;
break;
}
temp=temp->next;
}
if(isUse==1){
for(int i=0;i<len;i++){
head=head->next;
}
return head;
}else{
return NULL;
}
}
};
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
ListNode* list=NULL,* head=NULL,*temp1=list1,*temp2=list2;
int flag=0;
while(list1!=NULL&&list2!=NULL){
if(list1->val<list2->val){
if(flag==0){
list=temp1;
head=list;
flag=1;
}else{
list->next=temp1;
list=temp1;
}
list1=list1->next;
temp1->next=NULL;
temp1=list1;
}else{
if(flag==0){
list=temp2;
head=list;
flag=1;
}else{
list->next=temp2;
list=temp2;
}
list2=list2->next;
temp2->next=NULL;
temp2=list2;
}
}
if(list1!=NULL){
if(list==NULL){
list=list1;
head=list;
}else{
list->next=list1;
}
}else if(list2!=NULL){
if(list==NULL){
list=list2;
head=list;
}else{
list->next=list2;
}
}
return head;
}
};
二叉树衍生题目(初试)
class Solution {
public:
vector<int> out;
vector<int> inorderTraversal(TreeNode* root) {
visit(root);
return out;
}
void visit(TreeNode* root){
if(root!=NULL){
visit(root->left);
out.push_back(root->val);
visit(root->right);
}
}
};
class Solution {
public:
int maxDepth(TreeNode* root) {
if(root!=NULL){
int leftLen=maxDepth(root->left);
int rightLen=maxDepth(root->right);
return leftLen>rightLen ? leftLen+1:rightLen+1;
}else{
return 0;
}
}
};
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if(root!=NULL){
TreeNode* left=invertTree(root->left);
TreeNode* right=invertTree(root->right);
root->left=right;
root->right=left;
return root;
}else{
return NULL;
}
}
};
class Solution {
public:
bool isSymmetric(TreeNode* root){
return isMirror(root->left,root->right);
}
bool isMirror(TreeNode* root1,TreeNode* root2) {
if(root1!=NULL&&root2!=NULL){
if(root1->val!=root2->val){
return false;
}
bool flag1=isMirror(root1->left,root2->right);
bool flag2=isMirror(root2->left,root1->right);
if(flag1==true&&flag2==true){
return true;
}else{
return false;
}
}else{
if(root1==NULL&&root2==NULL){
return true;
}else{
return false;
}
}
}
};
class Solution {
public:
int ans;
int depth(TreeNode* rt){
if (rt==NULL) {
return 0; // 访问到空节点了,返回0
}
int L=depth(rt->left); // 左儿子为根的子树的深度
int R=depth(rt->right); // 右儿子为根的子树的深度
ans=max(ans,L+R+1); // 计算d_node即L+R+1 并更新ans
return max(L,R)+1; // 返回该节点为根的子树的深度
}
int diameterOfBinaryTree(TreeNode* root) {
ans=1;
depth(root);
return ans-1;
}
};
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
//父节点入栈
queue<TreeNode*> q;
vector<vector<int> > ans;
vector<int> v;
//处理空树
if(root==NULL) return ans;
q.push(root);
while(!q.empty()){
int n=q.size();
for(int i=0;i<n;i++){ //为了一口气处理完,队列里面的
TreeNode* temp=q.front();
q.pop();
v.push_back(temp->val);
if(temp->left!=NULL) q.push(temp->left);
if(temp->right!=NULL) q.push(temp->right);
}
ans.push_back(v);
v.clear();
}
return ans;
}
};