知识点复习

本文深入探讨C/C++编程中的关键概念,包括Next数组值计算、数字组合问题、循环输入输出、内联函数、栈、链表、快速排序、希尔排序及进制转换等核心主题。文章提供丰富的代码示例,帮助读者理解并掌握这些复杂概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、C/C++知识库

1.Next数组值计算方法

序号123456
字符串aaabca
next数组值012311
  • 前两个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'比较,不同;则再找序号3next(=2),再拿序号4的'b'与序号2的'a'比较,不同;则再找序号2next(=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)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值