一、C/C++知识库
1.Next数组值计算方法
序号 | 1 | 2 | 3 | 4 | 5 | 6 |
字符串 | a | a | a | b | c | a |
next数组值 | 0 | 1 | 2 | 3 | 1 | 1 |
- 前两个next[1]=0、next[2]=1这是确定的;
- 序号3找序号2对应的next(=1),即拿序号2的'a'与序号1的'a'比较,相同,则序号3的next值+1,即为2;
- 序号4找序号3对应的next(=2),即拿序号3的'a'与序号2的'a'比较,相同,则序号4的next值+1,即为3;
- 序号5找序号4对应的next(=3),即拿序号4的'b'与序号3的'a'比较,不同;则再找序号3的next(=2),再拿序号4的'b'与序号2的'a'比较,不同;则再找序号2的next(=1),再拿序号4的'b'与序号1的'a'比较,不同;比较至首部,仍然找不到相同的,则next=1;
- 序号6找序号5对应的next(=1),即拿序号5的'c'与序号1的'a'比较,不同;已到首部,next=1;
2.数字组合问题
- 题目:零钱有1元、5元、10元、20元、50元、100元,每种都有数张,购买M元的商品,不找零的付钱方法。
- 输入:第一行6个整数,分别代表1元、5元、10元、20元、50元、100元的数目。如6 5 4 3 2 1就分别代表有6张1元,5张5元,4张10元……
- 输出:各种人民币组合的长度之和。
输入:
6 5 4 3 2 1
11
输出:
12
/*‘01’转换法
* 参考网址:https://blog.youkuaiyun.com/hf19931101/article/details/79452799
* */
#include<iostream>
#include<vector>
using namespace std;
vector<vector<int>> all_list;//用于存放所有可能的组合
/*判断size个1是否全部移动到vector右边*/
bool right_1_size(vector<int> list,int size)
{
for(int i=list.size()-size;i<list.size();i++)
{
if(list[i]!=1)
return false;
}
return true;
}
/*vector中搜索size个数的和是否为nr,返回所有组合的个数,程序中剔除了重复的组合*/
int search_compose(vector<int> rmb,int size,int nr)
{
vector<int> index_list;
vector<int> t_list; //存放每一个暂时生成的list
/*建立size个1的索引列表index_list,用于检测index_list中为1的rmb对应位置和是否为nr*/
for(int i=0;i<size;i++)
{
index_list.push_back(1);
}
for(int i=size;i<rmb.size();i++)
{
index_list.push_back(0);
}
/*求解index_list中1对应rmb位置的和t_rmb*/
int n=0;
int t_rmb=0;
for(int i=0;i<rmb.size();i++)
{
if(index_list[i]==1)
{
t_rmb+=rmb[i];
}
}
/*判断t_rmb==nr,并且排除重复的组合*/
if(t_rmb==nr)
{
for(int i=0;i<index_list.size();i++)
{
//cout<<index_list[i]<<" ";
if(index_list[i]==1)
t_list.push_back(rmb[i]);//暂时存放index_list中1对应rmb位置的组合vector(即t_list)
}
//cout<<endl;
/*判断t_list是否在all_list里面*/
int flag=0;
for(int i=0;i<all_list.size();i++)
{
if(t_list==all_list[i])
{
flag=1;
break;
}
}
/*判断t_list是否在all_list里面,flag==0表示t_list不在all_list里面,同时将t_list添加到all_list中*/
if(flag==0)
{
n += 1;
all_list.push_back(t_list);
}
}
while(!right_1_size(index_list,size))
{
//从左到右扫描vector
for(int i=0;i<index_list.size()-1;i++)
{
if(index_list[i]==1&&index_list[i+1]==0)
{
//交换01的位置
int temp=index_list[i];
index_list[i]=index_list[i+1];
index_list[i+1]=temp;
//将"01"组合左边的1移到最左边
int cout=0;
for(int j=0;j<i;j++)
{
if(index_list[j])//满足index_list[j]==1才会
{
index_list[j]=0;//index_list[j]设定为0,index_list[cout++]同时设定为1,保证index正常移动,这里实际通过赋值实现移动
index_list[cout++]=1;
}
}
break;
}
}
int total_rmb=0;
for(int i=0;i<rmb.size();i++)
{
if(index_list[i]==1)
{
total_rmb+=rmb[i];
}
}
vector<int> x_list;
if(total_rmb==nr)
{
for(int i=0;i<index_list.size();i++)
{
//cout<<index_list[i]<<" ";
if(index_list[i]==1)
x_list.push_back(rmb[i]);
}
//cout<<endl;
int fg=0;
for(int i=0;i<all_list.size();i++)
{
if(x_list==all_list[i])
{
fg=1;
break;
}
}
if(fg==0)
{
n += 1;
all_list.push_back(x_list);
}
}
}
return n;
}
int main(int argc,char * argv[])
{
int temp;
vector<int> rmb_num;
for(int i=0;i<6;i++)
{
cin>>temp;
rmb_num.push_back(temp);
}
int need_rmb;
cin>>need_rmb;
vector<int> rmb_cls = {1,5,10,20,50,100};
vector<int> rmb;
/*根据商品需要的钱need_rmb,判断比need_rmb小的所有币种,并将拥有的rmb按照从小到大的方式放入vector*/
for(int i=0;i<rmb_cls.size();i++)
{
if(need_rmb>rmb_cls[i])
{
for(int j=0;j<rmb_num[i];j++)
{
rmb.push_back(rmb_cls[i]);
}
}
}
int rmb_size=rmb.size();
int num=0;
while(rmb_size)//保证能够查找到所有可能组合,rmb.size()->1
{
num += search_compose(rmb,rmb_size,need_rmb);
rmb_size--;
}
int all_size=0;
for(int i=0;i<all_list.size();i++)
{
all_size+=all_list[i].size();
//for(int j=0;j<all_list[i].size();j++)
// cout<< all_list[i][j]<<" ";
//cout<<endl;
}
cout<<all_size<<endl;
return 0;
}
3.循环输入输出
/* 输入:qwe
* 输出:qwe
* 输入:qwe 123
* 输出:
* qwe
* 123
* 输入:qwe 123 rty
* 输出:
* qwe
* 123
* rty*/
#include<iostream>
#include<vector>
#include<string>
using namespace std;
int main(int argc,char * argv[])
{
string s;
while(cin>>s)
{
cout<<s<<endl;
}
return 0;
}
cin输入,遇到(空格、回车、制表符)即会当做输入结束;
getline输入,遇到(换行符)即会当做输入结束,输入(空格、制表符)会当做其中一个字符;
string以及vector都可以采用size()获取长度:
string s="abc"; string s2("abc"); auto s_size = s.size();
vector<string> v={"abc","bcd"}; vector<string> v1{"abc","bcd"}; auto v_size=v.size()
vector<int> v2(10);//10个元素,每个数是0
vector<int> v3{10};//1个元素,为10
vector<int> v4(10,1);//10个元素,每个数是1
vector<int> v4{10,1};//2个元素,分别是10,1
4.cctype头文件中判断数字、字母、控制字符等
decltype获取变量类型
int a = 0;
//b:int,decltype的值就是表达式的类型本身
decltype (a) b = 1;
5.内联函数
频繁调用小函数时,调用函数比求等价表达式要慢很多,原因:调用前要先保存寄存器,并在返回时恢复;可能需要拷贝实参,程序会转向一个新的位置继续执行。
解决方案:内联inline,如inline const string &shortString(const string &s1,const string &s2){return s1.size()<s2.size()?s1:s2;}
但内联说明只是向编译器发出请求,编译器可能会忽略。
- 类内部的函数都是隐式的inline函数
6.指针和常量const
常量指针:int const * p或者 const int* p (指向常量的指针,指向的值不能修改)
指针常量:int * const p (指针就是常量,指向的值是可以修改的,只是指针的地址是常量(不变))
指向常量的指针常量:const int* const p (指针地址和指针指向的量都不能变化)
7.传递参数(函数)
传引用:int max(int &i, int &j){return i>j?i:j;}这里相当给传递的参数分别起一个别名i,j,其本质就是参数自己。
- 优点1:避免参数拷贝,特别如果参数是对象(类的实例),拷贝会非常大;直接引用,就可以直接操作原对象;
- 优点2:对于无法拷贝的参数,如IO类参数,则可以通过传引用解决;
- 优点3:需要return多个变量时,传递引用参数。函数执行以后,直接读引用参数的值,就已经更新。
8.类
类中的成员函数,如果用到this,表示指向“当前正在使用的对象”的指针。
9.栈
参考网站:https://blog.youkuaiyun.com/u011068702/article/details/54136375
先进后出
c++ stl栈stack的头文件为:
- #include <stack>
c++ stl栈stack的成员函数介绍
- empty() 堆栈为空则返回真
- pop() 移除栈顶元素 (删除)
- push() 在栈顶增加元素 (增加)
- size() 返回栈中元素数目
- top() 返回栈顶元素,不删除(获取)
例子:走迷宫(小红书)
测试用例:
5 10 20
1 4
0 3
2 2
4 4
1 7
1 3
2 3
1 8
3 7
3 5
1 5
0 9
4 8
4 0
4 1
2 1
0 7
0 4
4 5
0 8
/* *
* m*n矩阵棋盘,每个棋盘位置坐标(x,y),将一颗棋子从左上角(0,0),移至右下角(m-1,n-1),棋子可以向相邻的上下左右移动,每个坐标只能经过一次,有多少条路径可以到达右下角?
下面的程序只是从左上角走到右下角,未得出路径条数。
* */
#include<iostream>
#include<vector>
#include<stack>
#include<typeinfo>
using namespace std;
struct POS{
int row;
int col;
};
int input_data(vector<vector<int>> &z,int k) //&z--引用,起别名
{
for(int i=0;i<k;i++)
{
int temp_x,temp_y;
vector<int> temp;
cin>>temp_x>>temp_y;
temp.push_back(temp_x);
temp.push_back(temp_y);
z.push_back(temp);
}
}
template<typename T>
void display_map(vector<vector<T>> &qmap)
{
for (int i=0;i<qmap.size();i++) //构建图:1表示有障碍物,0表示可通过
{
for(int j=0;j<qmap[i].size();j++)
cout<<qmap[i][j]<<" ";
cout<<endl;
}
}
int dfs_t(vector<vector<int>> &qmap)
{
stack<POS> s;
POS pos={0,0};
POS temp_pos={0,0};
s.push(pos);
if(qmap[0][0]==0)
{
qmap[0][0]=2;//[0][0]位置已被查看
int k=0;
while(!s.empty())
{
pos = s.top();//出栈表示已走
//s.pop();
if(pos.row==qmap.size()-1 && pos.col==qmap[0].size()-1)//边界条件,到达右下角点
{ break;}
else if(pos.row+1<qmap.size() && qmap[pos.row+1][pos.col]==0)//下
{
temp_pos = {pos.row+1,pos.col};
s.push(temp_pos);
qmap[temp_pos.row][temp_pos.col]=2;
}
else if(pos.col+1<qmap[0].size()&&qmap[pos.row][pos.col+1]==0)//右
{
temp_pos = {pos.row,pos.col+1};
s.push(temp_pos);
qmap[temp_pos.row][temp_pos.col]=2;
}
else if(pos.row-1>=0 && qmap[pos.row-1][pos.col]==0)//上
{
temp_pos = {pos.row-1,pos.col};
s.push(temp_pos);
qmap[temp_pos.row][temp_pos.col]=2;
}
else if(pos.col-1>=0 && qmap[pos.row][pos.col-1]==0)//左
{
temp_pos = {pos.row,pos.col-1};
s.push(temp_pos);
qmap[temp_pos.row][temp_pos.col]=2;
}
else//表示到达当前位置后,不能再向上、下、左、右移动,出栈
{
s.pop();
}
cout<<"第"<<k++<<"次:"<<endl;
display_map(qmap);
}
//上述while循环,最终会保留一条可以走通的路径
cout<<"迷宫路线:"<<endl;
while(!s.empty())//输出迷宫线路
{
pos = s.top();
cout<<pos.row<<" "<<pos.col<<endl;
s.pop();
}
}
else{
cout<<0<<endl;
}
}
int main()
{
int n,m,k;
cin>>n>>m>>k;
vector<vector<int>> z;
input_data(z,k);
cout<<endl;
//for(int i=0;i<z.size();i++)
//{
// cout<<z[i][0]<<" "<<z[i][1]<<endl;
//}
vector<vector<int>> qmap(n,vector<int>(m));//m列n行,初始化默认是0
for(int i=0;i<z.size();i++)
{
qmap[z[i][0]][z[i][1]]=1;
}
cout<<"qmap.size:"<<qmap.size()<<endl;
display_map(qmap);
dfs_t(qmap);
return 0;
}
深度搜索dps找出所有连通域,如下:(4个‘O’连通域,程序只将内部2个连通域找出来,改为'X')
{'X','X','X','X','X'},
{'X','O','O','X','O'},
{'X','O','X','X','X'},
{'X','X','O','X','X'},
{'X','X','O','X','X'},
{'X','O','X','X','X'}
#include<iostream>
#include<vector>
#include<stack>
#include<queue>
struct point{
int row;
int col;
};
using namespace std;
template<typename T>
void p_chess(vector<vector<T> > &chess)
{
for(int i=0;i<chess.size();i++)
{
for(int j=0;j<chess[i].size();j++)
cout<<chess[i][j]<<" ";
cout<<endl;
}
}
int main()
{
vector<vector<char>> chess={{'X','X','X','X','X'},
{'X','O','O','X','O'},
{'X','O','X','X','X'},
{'X','X','O','X','X'},
{'X','X','O','X','X'},
{'X','O','X','X','X'}};
vector<vector<int>> t_chess(chess.size(),vector<int>(chess[0].size()));//临时chess保存找出的‘O’
//p_chess(t_chess);
//cout<<endl;
p_chess(chess);
point p={0,0};
stack<point> s_p;
vector<point> tmp_p;//存储非边缘连通域中找到的第一个点位置坐标--“连通域代表点”
for(int i=1;i<chess.size()-1;i++)
{
for(int j=1;j<chess[i].size()-1;j++)
{
if(chess[i][j]=='O'){
t_chess[i][j]=2;//将chess中‘0’的位置对应到t_chess中的位置,并存为2之后,其连通域即可限制tmp_p存入重复的“连通域代表点”
if(t_chess[i-1][j]!=2 && t_chess[i][j-1]!=2 && t_chess[i+1][j]!=2 && t_chess[i][j+1]!=2)
{
p.row=i;
p.col=j;
tmp_p.push_back(p);
}
}
}
}
//tmp_p存入了非边缘的连通域代表点(也就是连通域的第一个点)
//for(int i=0;i<tmp_p.size();i++)
//{
// cout<<tmp_p[i].row<<" "<<tmp_p[i].col<<endl;
//}
for(int i=0;i<tmp_p.size();i++)
{
p = tmp_p[i];
s_p.push(p);
chess[p.row][p.col]='Y';
//每个连通域都分别深度搜索,直至找完当前连通域的所有'O'
while(!s_p.empty())
{
p = s_p.top();
point t_p;
if(p.row==chess.size() && p.col==chess[0].size())
break;
else if(p.row+1<chess.size() && p.col<chess[0].size() && chess[p.row+1][p.col]=='O')//下
{
t_p = {p.row+1,p.col};
s_p.push(t_p);
chess[t_p.row][t_p.col]='Y';
}
else if(p.row<chess.size() && p.col+1<chess[0].size() && chess[p.row][p.col+1]=='O')//右
{
t_p = {p.row,p.col+1};
s_p.push(t_p);
chess[t_p.row][t_p.col]='Y';
}
else if(p.row>=0 && p.col-1>=0 && chess[p.row][p.col-1]=='O')//左边
{
t_p = {p.row,p.col-1};
s_p.push(t_p);
chess[t_p.row][t_p.col]='Y';
}
else if(p.row-1>=0 && p.col>=0 && chess[p.row-1][p.col]=='O')//上边
{
t_p = {p.row-1,p.col};
s_p.push(t_p);
chess[t_p.row][t_p.col]='Y';
}else
s_p.pop();
cout<<endl;
p_chess(chess);
}
}
for(int m=0;m<chess.size();m++)
{
for(int n=0;n<chess[0].size();n++)
{
if(chess[m][n]=='Y')
chess[m][n]='X';
}
}
cout<<endl;
p_chess(chess);
return 0;
}
输出:
X X X X X
X X X X O
X X X X X
X X X X X
X X X X X
X O X X X
10.链表
创建一个单向链表,并循环输出链表每个节点的数据项;
#include<iostream>
#include <stdlib.h>
#include<vector>
using namespace std;
struct node{
int data;
node *next;
};
void p_L(node *L)
{
while(L->next!=NULL)
{
cout<<L->data<<"->";
L = L->next;
}
cout<<L->data<<endl;//这里必须再次输出一项,上面while循环判断到最后一个节点的next指向NULL就结束了,所以没有输出最后一项。
}
void create_L(node* L,vector<int> &list)
{
node *q,*p;
q=L;
for(int i=0;i<list.size();i++)
{
//p用于创建节点,q用于移动
p = (node*)malloc(sizeof(node));
p->data=list[i];
q->next = p;
q = p;
}
q->next=NULL;
}
int main()
{
node *head;
head = (node *)malloc(sizeof(node));//malloc分配一段动态存储区,返回首地址(所以前面要用*,存储的node类型)
head->data = 0;
head->next = NULL;//链表头部,数据项为0,next暂时指向NULL
vector<int> list={9,8,7,6,5,4,3,2,1};
create_L(head,list);
p_L(head);
return 0;
}
输出:0->9->8->7->6->5->4->3->2->1(头部数据项存储的0)
11.快速排序
面试还是遇到了手写快排,赶紧踏实一点,认真实现一下每个细节!
#include<iostream>
#include<vector>
using namespace std;
void p_array(const int *array,int size)
{
for(int i=0;i<size;i++)
cout<<array[i]<<" ";
cout<<endl;
}
void swap(int &x, int &y)
{
int temp=x;
x=y;
y=temp;
}
//1轮循环
void f_sort(int array[],int l,int h)
{
if(l>=h) return; //结束
int &key = array[l];
int i=l;
int j=h;
//这是1轮循环,容易搞懵,先写一轮
while(1)
{
while(array[--j]>=key && i<j);//右->左,找到1个比key小的数,j为当前索引
while(array[++i]<=key && i<j);//左->右,找到1个比key大的数,i为当前索引
cout<<"i:"<<i<<" j:"<<j<<endl;
if(i>=j) break; //i与j相遇时,结束循环
swap(array[i],array[j]);//交换找到的比key大(left),比key小(right)的数
}
swap(array[j],key);
f_sort(array,l,j-1);
f_sort(array,j+1,h);
}
int main()
{
int array[]={4,5,2,9,1,6,3,8,3};
int arr_len=sizeof(array)/sizeof(array[0]);
p_array(array,arr_len);
int l=0;
int h=arr_len;
f_sort(array,l,h);
p_array(array,arr_len);
return 0;
}
12.希尔排序
13.进制转换(商汤笔试)
ps:仅测试例子通过!未来得及测试全部!输入:19 13,输出:16
import math
def translate(num,base_num): #10进制数num转换为base_num进制
if num < base_num:
return str(num)
else:
n = int(math.log10(num)/math.log10(base_num))+1
trans_num = ''
for i in range(n):
num_add = num/(base_num**(n-i-1))
trans_num = trans_num + str(num_add)
num = num - num_add*(base_num**(n-i-1))
return trans_num
if __name__ == '__main__':
a = raw_input()
data1 = int(a.split(' ')[0])
data2 = int(a.split(' ')[-1])
num = 0
t = 10
while(t):
t = t+1
x = translate(data1,t)
str_x = str(x)
if (len(str_x)==len([str_x[j] for j in range(len(str_x)) if str_x[j]>='0' and str_x[j]<='9'])) is True:
num = t
if int(x)<data2:
break
print(num-1)