C++算法竞赛常用函数及算法

C++算法竞赛常用函数及算法

一、 string类在算法中的常见用法

构造,赋值,存取,拼接,查找,替换,比较,子串,插入,删除
#include
#include 
//#include
//#include
using namespace std;
string s="string";
char a[20]={"char[]"};
int main(){
	//1、字符串拼接  
	//支持使用 + 连接字符串 
	
    //2、字符串输入输出
    //cin >> s; //输入Hello World! cin是以空格,回车作为结束输入的标志
    //cout<< s <
    
    //3、读取一行字符(cin.getline())
	//cin.getline定义在下,如:a[n] 则最多读取 n-1个字符 
	//cin.getline(a,8);
	
    //4、获取字符串的长度
	//size() , length()
	
    //5、可以把字符串当成字符数组使用

    //6、字符串与字符数组的互换,C-风格的字符数组可以与字符串互相转换 
    //字符串转字符数组
    //内置函数 copy 
    //int lens = s.copy(a,s.size());
    //a[lens] = '\0';
    //strcpy 函数 
   	//strcpy(a,s.c_str());//头文件使用 cstring 
    //字符数组转字符串
    //string s(a);

    //7、字符串的比较 ,数组用strcmp(),相等为0,不等为1 (或者循环遍历)

    //8、字符串的子串(截取字符串) substr()
	//cout<
	
    //9、查找字符串的子串 find()
    //cout<
    //cout<

    //10、替换字符串 replace(起始位置,个数,"替换内容")
    //s.replace(3,1,"XI");// 输出 strXI
    //指定替换
    //int n=s.find("t");
    //s.replace(n,3,"HUA");// 输出 sHUAIng
    
    //11、删除子串
    //s.erase(position,nummer); //起始位置,删除个数 

    //12、添加子串
    //s.insert(5,"aaa");//5表示位置 "aaa"表示增加的字符串 ,输出 strinaaag 
    
    //13、reverse 反转函数 
	//reverse(s.begin(),s.end());// 使用头文件  
	
	//14、sort 排序
	//sort(s.begin(),s.end());// 使用头文件  
	return 0;
}

二、 sort自定义排序(结构体,数字)

#include
#include
using namespace std;
bool cmp(int x,int y){
	return x < y;
}
struct Student{
	string name;
	int score;
	Student() {}
	Student(string n,int s):name(n),score(s) {}
};
bool cmp_score(Student x,Student y){
	return x.score>y.score;
}
int main(){
	//自定义排序
	//1、对整型数组的排序 
	int num[5] = {1,2,3,5,4};
	sort(num,num+5,cmp);
	for(int i=0;i<5;i++){
		cout<<num[i]<<" ";
	}
	
	//2、对结构体排序  
	Student stu[3];
	stu[0]=Student("小希",100);
	stu[1]=Student("小乐",88);
	stu[2]=Student("小明",95);

	sort(stu,stu+3,cmp_score);
	cout<<endl; 
	for(int i=0;i<3;i++){
		cout<<stu[i].name<<" "<<stu[i].score<<endl;
	}
	return 0;
} 

三、 max_element()和min_element() 寻找最值

使用vector(数组类似)
#include 
#include 
#include 
#define pb push_back
using namespace std;
int main() {
	vector<int> v;
	int n;
	cin >> n;
	while (n--) {
		int num;
		cin >> num;
		v.pb(num);
	}
	auto minv = min_element(v.begin(), v.end());
	auto maxv = max_element(v.begin(), v.end());
	cout << *minv << " " << *maxv;
	return 0;
}

四、二分查找的函数

C++的头文件algorithm中有用于二分查找的函数,分别为lower_bound()upper_bound()以及binary_search()

使用这些函数的前提是数组必须是有序的(升/降)

lower_bound():返回大于或等于目标值的第一个位置
upper_bound():返回大于目标值的第一个位置
binary_search():若目标值存在则返回true,否则返回false

这三个函数都有三个参数:分别为数组的起始位置、数组的终止位置(取不到)以及要查找的目标值,返回值为物理地址,因此要获得对应的逻辑地址,需要减去数组的起始位置。

#include
#include
using namespace std;
int a[8] = {1, 2, 4, 4, 5, 8, 10, 22};
int main(){
    int x = lower_bound(a, a + 8, 4)-a;
    int y = upper_bound(a, a + 8, 4)-a;
    bool z = binary_search(a, a + 8, 4);
    cout<<x<<" "<<y<<" "<<z<<endl; //输出 2 4 1
    return 0;
}
二分查找算法

核心思想:不断缩小搜索区域,降低查找目标元素的难度

以在升序序列中查找目标元素为例,二分查找算法的实现思路是:

  1. 初始状态下,将整个序列作为搜索区域(假设为 [B, E]);
  2. 找到搜索区域内的中间元素(假设所在位置为 M),和目标元素进行比对。如果相等,则搜索成功;如果中间元素大于目标元素,表明目标元素位于中间元素的左侧,将 [B, M-1] 作为新的搜素区域;反之,若中间元素小于目标元素,表明目标元素位于中间元素的右侧,将 [M+1, E] 作为新的搜素区域;
  3. 重复执行第二步,直至找到目标元素。如果搜索区域无法再缩小,且区域内不包含任何元素,表明整个序列中没有目标元素,查找失败。

五、tolower(),toupper()大小写转换

#include
#include
#include
using namespace std;
void mytolower(char *s){
    int len=strlen(s);
    for(int i=0;i<len;i++){
        if(s[i]>='A'&&s[i]<='Z'){
            s[i]=tolower(s[i]);
            //s[i]+=32;//+32转换为小写
            //s[i]=s[i]-'A'+'a';
        }
    }
}
void mytoupper(char *s){
    int len=strlen(s);
    for(int i=0;i<len;i++){
        if(s[i]>='a'&&s[i]<='z'){
            s[i]=toupper(s[i]);
            //s[i]-=32;//+32转换为小写
            //s[i]=s[i]-'a'+'A';
        }
    }
}
int main() {
    cout<<"请输入一个含大写的字符串:";
    char s[201];
    gets(s);
    mytolower(s);
    cout<<"转化为小写后为:"<<s<<endl;
    mytoupper(s);
    cout<<"转化为大写后为:"<<s<<endl;
    return 0;
}

六、 全排列函数( next_permutation() )

#include  
#include  
using namespace std;  
int main()  
 {  
    int num[3]={1,2,3};  
    do{  
        cout<<num[0]<<" "<<num[1]<<" "<<num[2]<<endl;       
	}while(next_permutation(num,num+3));
	/* 输出: 
		1 2 3
		1 3 2
		2 1 3
		2 3 1
		3 1 2
		3 2 1
	*/
    return 0;  
 }

七、 动态规划(dp)

动态规划(Dynamic Programming,简称 DP)是一种求解决策过程中的最优化问题的方法,它的核心思想是将大问题分解为小问题进行求解,再从这些小问题的答案构建大问题的答案。
动态规划的基本思路:

  1. 划分子问题:将原问题分解为多个相似的子问题。子问题之间通常存在依赖关系。
  2. 存储子问题的解:每个子问题只解决一次,并将答案存储在一个表格中,这样在需要时可以直接查找,不必重新计算。
  3. 自底向上的计算:根据子问题之间的依赖关系,从小的子问题开始计算,直到得到原问题的答案。

动态规划的关键要素:

  1. 状态:表示问题的某种局部情况或属性。
  2. 状态转移方程:描述了状态之间如何转移,或者说如何从一个或多个已知状态得到另一个状态的解。
  3. 初始状态和边界状态:问题的最小子问题的答案以及边界情况。

动态规划的步骤:

  1. 定义子问题。
  2. 实现要存储子问题解的数据结构。
  3. 找到状态转移方程。
  4. 确定初始状态和边界状态。
  5. 自底向上计算。

动态规划与递归和分治的区别:

  1. 递归:是一种程序调用自身的编程技巧。
  2. 分治:是一种将问题分解为独立的子问题来解决的策略。
  3. 动态规划:与分治类似,但是子问题不是独立的,动态规划需要存储子问题的解来避免重复计算。

八、 贪心算法

贪心算法是算法设计中的一种方法,它在每一步选择中都采取在当前看来最好的选择,也就是局部最优选择,以希望这样的选择能导致全局最优解。
贪心算法的特点:

  1. 局部最优选择:在每个决策点,选择当前最佳的解决方案,而不考虑此选择会导致的后果。
  2. 不回退( 无后效性 ):一旦做出选择,就不再改变,也就是说它不像回溯算法那样能返回上一步。

贪心算法的基本结构:

  1. 从问题的某一初始解出发。采用循环结构,当可以向求解目标前进一步时:

  2. 选择当前状态下的最佳选择。更新当前状态,通常是向前一步。

  3. 直到达到问题的一个解为止。

贪心算法与动态规划的区别:

  1. 解决问题的角度:贪心算法是从前往后,每步都采取局部最优选择,希望通过每一步的局部最优得到全局最优;而动态规划则是基于子问题的最优解,通过已知的子问题的最优解推导出全局最优解。
  2. 是否保存子问题的解:动态规划需要保存子问题的解以避免重复计算,而贪心算法则不需要。
  3. 应用范围:贪心策略对某些问题能得到整体最优解,但对某些问题不能。动态规划则可以保证得到全局最优解,但可能需要更多的计算和存储空间。

虽然贪心算法不能保证总是得到整体最优解,但由于其高效性,它在很多情况下仍然是一个非常有用的方法。当然,确定一个问题是否适合使用贪心策略是非常关键的。

你可能感兴趣的:(C/C++备战蓝桥杯,c++,算法,开发语言)