刷题(二)C++实现

题目一

给定一个数组arr,求差值为k的去重数字对。

思路

对于数组中的每个值,使用STL里面的find查找是否有与之差值为k的值存在,如果存在,则在用于标记的数组mark中将该数字的索引位置标为1.最后将每个索引位置被标为1的值存入set容器中进行去重。

实现代码

#include<iostream>
#include<vector>
#include<algorithm>
#include<set>
using namespace std;

set<int> remove(vector<int>&nums, int k){

	vector<int>mark(nums.size());
	//找到相应的数字,记录数字的索引位置
	for(int i=0;i<nums.size();i++){
		if((find(nums.begin(), nums.end(),nums[i]-k)!=nums.end())||
			(find(nums.begin(), nums.end(),nums[i]+k)!=nums.end())){
			mark[i]=1;
		}		
	}
	
	//放到set里面,自动去重
	set<int>answer;
	for(int i=0; i<nums.size(); i++){
		if(mark[i])
			answer.insert(nums[i]);
	}

	return answer;
}

int main(){
	vector<int>nums={3,16,53,72,33,1,6,7,3,73,146,23,64,1,78,52};
	int k=13;
	set<int>answer=remove(nums, k);
	for(auto i : answer)
		cout<<i<<endl;

	return 0;

}

加题

如果两个只包含小写英文字母的字符串所含字符种类相同,则这两个字符串被称为同源词。比如“ab”和“abbba”就是同源词。“ab”和“abbbbc”就不是同源词。

写一个函数,判断两个词是否为同源词

思路

还是用set。分别村两个字符串的各个字符。如果两个set容器的size相同,则两个词是同源词。(这个太简单,就不实现了)

或者使用26位二进制代表一个词,每一位对应一个字母。如果两个字符串对应的数相同,则说明两个词是同源词。

实现代码:

#include<iostream>
using namespace std;

void compare(string first, string second){
	int num1=0, num2=0;

	for(int i=0; i<first.length(); i++){
		num1 |= 1<<(first[i]-'a');
	}

	for(int j=0; j<second.length(); j++){
		num2 |=1<<(second[j]-'a');
	}
	
	if(num1==num2)
		cout<<"两个字符串同源"<<endl;
	else
		cout<<"两个字符串不同源"<<endl;
}

int main(){
	string first, second;
	cout<<"请输入一个由小写字母组成的字符串"<<endl;
	cin>>first;
	cout<<"请再次输入一个由小写字母组成的字符串"<<endl;
	cin>>second;

	compare(first, second);
	return 0;
}

题目二

给一个包含n个整数元素的集合a,一个包含m个整数元素的集合b。定义magic操作为,从一个集合中取出一个元素,放到另一个集合里,且操作过后每个集合的平均值都大大于于操作前。
注意以下两点:

  • 1)不可以把一个集合的元素取空,这样就没有平均值了
  • 2)值为x的元素从集合b取出放入集合a,但集合a中已经有值为x的元素,则a的平均值不变(因为集合元素不会重复),b的平均值可能会改变(因为x被取出了)

问最多可以进行多少次magic操作?

思路:

集合,因此不会存在重复值。

对于集合a和集合b,如果两个集合的平均值相同,则无法进行此操作

实现magic操作的方法是拿出平均值高的那个集合里,值小于该集合的平均值且高于另一个集合的平均值的值,且该值在平均值小的集合中并没有出现过(因为集合中元素不会发生重复)。则会发生magic操作。

实现代码:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

//要取得[a,b)的随机整数,使用(rand() % (b-a))+ a; 
//要取得[a,b]的随机整数,使用(rand() % (b-a+1))+ a;
int CreatRandomNum(){
	//随机产生1到100的整数
	return (rand() % 100)+1;	
}

int magic(vector<int>a, vector<int>b){
	int sum_a=0, sum_b=0;
	for(auto i : a) sum_a+=i;
	for(auto i : b) sum_b+=i;
	
	double ave_a=sum_a/a.size();
	double ave_b=sum_b/b.size();

	if(ave_a==ave_b) return 0;
	sort(a.begin(),a.end());
	sort(b.begin(),b.end());
	
	int answer=0;
	//从a往b拿
	if(ave_a>ave_b){
		for(int i=0; i<a.size();i++){
			//该值大于b的均值且小于a的均值,且在b中没出现过
			if((a[i]>ave_b)&&(a[i]<ave_a)&&(find(b.begin(),b.end(),a[i])==b.end())){
				answer++;
			}
		}
	}
	//从b往a拿
	else{
		for(int i=0; i<b.size();i++){
			//该值大于a的均值且小于b的均值,且该值在a中没出现过
			if((b[i]>ave_a)&&(b[i]<ave_b)&&(find(a.begin(),a.end(),b[i])==a.end())){
				answer++;
			}
		}
	}
	return answer;
}

int main(){
	vector<int>a, b;
	int len_a=CreatRandomNum(), len_b=CreatRandomNum();
	while(len_a--)
		a.push_back(CreatRandomNum());
	while(len_b--)
		b.push_back(CreatRandomNum());
	
	int answer=magic(a,b);
	cout<<answer<<endl;
	return 0;
}

题目三

将给定的数转换为字符串,原则如下:1对应 a,2对应b,…..26对应z,

例如12258可以转换为"abbeh", "aveh", "abyh", "lbeh" and "lyh",个数为5,

编写一个函数,给出可以转换的不同字符串的个数。

思路:

暴力递归解思路(配合后面的代码更容易理解):

对于字符串,遍历每个字符:

  1. 如果当前位置为字符串的结尾位置,则只有一种表达方式——空串。
  2. 如果当前字符是“0”,则无法转换,因为1111可以转成aaaa,也可以11和11组合。但是字符以0开头,没有对应的字符
  3. 如果开头不是“0”,且后续有字符。只要该位置不是“0”,则结果sum=1(该位置的字符自己表示一个字母)+余下的组合方式
  4. 当遍历到字符串的末尾,则结束递归。

动态规划解法——dp只是用来记录每一步的最优解的一个容器

实现代码:

#include<iostream>
#include<string>
#include<vector>
using namespace std;

//产生一个10000-100000的随机数
int CreatRandomNum(){
	/*
	要取得[a,b)的随机整数,使用(rand() % (b-a))+ a; 
	要取得[a,b]的随机整数,使用(rand() % (b-a+1))+ a; 
	要取得(a,b]的随机整数,使用(rand() % (b-a))+ a + 1; 
	*/
	return (rand()%90000)+10000;
}

//暴力递归
int Process(string input, int index){
	if(index==input.length()) return 1;
	if(input[index]=='0') return 0;

	int res=Process(input, index+1);
	if(index==input.length()-1) return res;
	if(((input[index]-'0')*10+input[index+1]-'0')<27)
		res+=Process(input, index+2);

	return res;
}

//动态规划
int dp(string input){
	//初始长度为input.length()+1,因为有可能会有空串的情况
	//应该把该结果放在动态规划数组索引位置为input.length()的位置,因此初始化长度为input.length()+1
	vector<int>con(input.length()+1);
	//把空串的情况存放在空串会发何时能的对应位置上
	//空串的时候,只有一种结果,所以此时的值为1
	con[input.length()]=1;
	//最后一位如果是0,则此处无解,否则此处是一种字母,结果为1
	con[input.length() - 1] = input[input.length() - 1] == '0' ? 0 : 1;

	for(int i=input.length()-2; i>=0; i--){
		//此时无法代表任何字符,因此次违章的结果为0
		if (input[i] == '0') con[i] = 0;
		else
			//当前字符不是"0"。如果此位置和下一个位置组合的值小于27,说明还能组合出一个结果
			con[i] = con[i + 1] + (((input[i] - '0') * 10 + (input[i + 1] - '0')) < 27 ? 
				con[i + 2] : 0);
	}
	return con[0];
}

int main(){
	
	//把数字转成字符串
	string input=to_string (CreatRandomNum());

	//暴力递归
	//cout<<Process(input, 0)<<endl;
		
	//动态规划
	//cout<<dp(input)<<endl;
   	cout<<input<<endl; 
    Process(input, 0)==dp(input)?cout<<"good"<<endl:cout<<"fucking !!! fuck!!!"<<endl;
    
	return 0;
}

未完待续 2019.2.27

猜你喜欢

转载自blog.csdn.net/qq_29996285/article/details/87970771