1、小v今年有n门课,每门都有考试,为了拿到奖学金,小v必须让自己的平均成绩至少为avg。每门课由平时成绩和考试成绩组成,满分为r。现在他知道每门课的平时成绩为ai ,若想让这门课的考试成绩多拿一分的话,小v要花bi 的时间复习,不复习的话当然就是0分。同时我们显然可以发现复习得再多也不会拿到超过满分的分数。为了拿到奖学金,小v至少要花多少时间复习。
在牛客上面没有通过,但是在本地运行的结果与牛客上的结果又是相同的,不知道是不是因为编译器的问题,有待之后进一步检查。
收获:对于sort函数的编写有了新的了解,其中第三个参数:cmp函数可以根据自己的要求进行编写,返回值是bool型,它规定了什么样的关系才是“小于”。
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct score_time {
int score;
int time;
};
int main() {
int len, totals, avg;
cin >> len >> totals >> avg;
vector<score_time> s;
score_time temp;
int i = len;
while (i > 0) {
cin >> temp.score >> temp.time;
s.emplace_back(temp);
i--;
}
int need_score = avg * len;
for (int i = 0; i < s.size(); i++) {
need_score -= s[i].score;
s[i].score = totals - s[i].score;
}
//定义sort函数比较规则
//比较函数是一个自己定义的函数,返回值是bool型,它规定了什么样的关系才是“小于”
//按照加一分需要的时间从小到大排序
sort(s.begin(), s.end(), [](const score_time& a, const score_time& b)->bool {
if (a.time == b.time) return a.score < b.score;
else return a.time < b.time;
});
if (need_score <= 0) cout << 0 << endl;
long min_time = 0;
for (int i = 0; i < s.size(); i++) {
if (need_score > s[i].score) {
min_time += s[i].score * s[i].time;
need_score -= s[i].score;
}
else {
min_time += need_score * s[i].time;
cout << endl;
cout << min_time << endl;
break;
}
}
return 0;
}
2、计算字符串最后一个单词的长度,单词以空格隔开。
输入:Hello world! 输出:5
收获:
在C++中本质上有两种getline函数:一种在头文件中,是istream类的成员函数;一种在头文件中,是普通函数。
1、 在中的getline()函数有两种重载形式:
istream& getline (char* s, streamsize n );
istream& getline (char* s, streamsize n, char delim );
作用是: 从istream中读取至多n个字符(包含结束标记符)保存在s对应的数组中。即使还没读够n个字符,如果遇到delim或 字数达到限制,则读取终止,delim都不会被保存进s对应的数组中。
2、第二种: 在中的getline函数有四种重载形式:
istream& getline (istream& is, string& str, char delim);
istream& getline (istream&& is, string& str, char delim);
istream& getline (istream& is, string& str);
istream& getline (istream&& is, string& str);
用法和上第一种类似,但是读取的istream是作为参数is传进函数的。读取的字符串保存在string类型的str中。
函数的变量:
is :表示一个输入流,例如cin。
str :string类型的引用,用来存储输入流中的流信息。
delim :char类型的变量,所设置的截断字符;在不自定义设置的情况下,遇到’\n’,则终止输入。
getline不是C库函数,而是C++库函数。它遇到以下情况发生会导致生成的本字符串结束:(1)到文件结束,(2)遇到函数的定界符,(3)输入达到最大限度。
- getline在while中作为条件判断,当如本例中getline(cin,str),当遇到换行时while循环结束,但是若** while (getline(cin, line,’#’))**则不一定跳出循环,因为while判断语句的真实判断对象是cin的状态,也就是判断当前是否存在有效的输入流。
#include<iostream>
#include<string>
using namespace std;
int main(){
string str;
while(getline(cin,str)){
int len=0,flag=1;
for(int i=str.size()-1;i>=0;i--){
//从后往前计算,要是末尾有空格,首先清楚末尾的空格
if(flag&&str[i]==' ') continue;
else if(str[i]!=' '){
flag=0;
len++;
}else break;
}
cout<<len<<endl;
}
return 0;
}
3、写出一个程序,接受一个由字母和数字组成的字符串,和一个字符,然后输出输入字符串中含有该字符的个数。不区分大小写。
收获: 看清题目要求,不区分大小写;
字母大小写转换:
- 对应大小写字母之间相差32,大写+32=小写;
- 利用toupper和tolower函数进行单个字母之间的大小写转换;
- 利用strupr、strlwr函数进行整个字符串中字母的大小写转换;
- 利用transform和tolower及toupper进行结合:
transform(str.begin(),str.end(),str.begin(),tolower);
transform(str.begin(),str.end(),str.begin(),toupper);
#include<iostream>
#include<string>
using namespace std;
int main(){
string str;
int times=0;
while(getline(cin,str)){
char tag;
cin>>tag;
for(int i=0;i<str.size();i++){
if(tolower(str[i])==tolower(tag)) times++;
}
}
cout<<times<<endl;
return 0;
}
4、明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N≤1000),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明完成“去重”与“排序”的工作(同一个测试用例里可能会有多组数据,希望大家能正确处理)。
收获:用空间换时间,将随机数作为数组的下标,然后顺序输出数组下标,即已经排序之后的结果。
#include<iostream>
#include<vector>
using namespace std;
int main(){
int N,num;
while(cin>>N){
int a[1001]={0};
while(N--){
cin>>num;//重复数字作为a数组下标的那个元素只保留一个
a[num]=1;
}
for(int i=1;i<1001;i++){
if(a[i]) cout<<i<<endl;
}
}
return 0;
}
5、连续输入字符串,请按长度为8拆分每个字符串后输出到新的字符串数组;长度不是8整数倍的字符串请在后面补数字0,空字符串不处理。
收获:对两个函数的使用更加熟悉了:str.substr(pos,n);从pos开始连续n个字符子串,当超过pos范围,会作出out-of-range的异常
str.append(n,args);在str末尾添加n个args字符;str.append(args);在str末尾添加一个字符或者字符串。
#include<string>
#include<iostream>
using namespace std;
int main(){
string str;
int N=2;
while(N--){
while(getline(cin,str)){
int len=str.size();
while(len>8){
cout<<str.substr(str.size()-len,8)<<endl;
len-=8;
}
str.append(8-len,'0');
cout<<str.substr(str.size()-8,8)<<endl;
}
}
return 0;
}
6、写出一个程序,接受一个十六进制的数,输出该数值的十进制表示。(多组同时输入 )
收获:while(cin>>hex>>a)可以连续输入a值
#include<iostream>
using namespace std;
int main(){
int a;
while(cin>>hex>>a){
cout<<a<<endl;
}
return 0;
}
7、功能:输入一个正整数,按照从小到大的顺序输出它的所有质因子(重复的也要列举)(如180的质因子为2 2 3 3 5 ),最后一个数后面也要有空格
收获:
1、判断从2到sqrt(n)是否存在其约数,时间复杂度O(sqrt(n));
2、判断2之后,就可以判断从3到sqrt(n)之间的奇数了,无需再判断之间的偶数,时间复杂度O(sqrt(n)/2);
3、大于等于5的质数一定和6的倍数相邻,在5到sqrt(n)中每6个数只判断2个,时间复杂度O(sqrt(n)/3);
4、0和1都不是质数。
#include<iostream>
#include<cmath>
using namespace std;
bool IsPrime(long num){
if(num==1) return false;
if(num==2||num==3) return true;
if(num%6!=1&&num%6!=5) return false;
float num_sqrt=floor(sqrt(num));
//在5到sqrt(n)中每6个数只判断2个
for(int i=5;i<=num_sqrt;i+=6){
if(num%i==0||num%(i+2)==0) return false;
}
return true;
}
int main(){
long num;
cin>>num;
if(num==1){
cout<<" "<<endl;
return 0;
}
while(!IsPrime(num)){
if(num==1){
cout<<endl;
break;
}
for(int i=2;i<=floor(sqrt(num));i++){
if(num%i==0){
cout<<i<<" ";
num/=i;
break;
}
}
}
if(num!=1) cout<<num<<" "<<endl;
return 0;
}
8、写出一个程序,接受一个正浮点数值,输出该数值的近似整数值。如果小数点后数值大于等于5,向上取整;小于5,则向下取整。
收获:floor() 向下取整(即最大不大于此数的整数);ceil() 向上取整(即最小不小于此数的整数);round() 四舍五入 取整
#include<iostream>
#include<cmath>
using namespace std;
int main(){
float num;
cin>>num;
cout<<round(num)<<endl;
return 0;
}
9、数据表记录包含表索引和数值(int范围的整数),请对表索引相同的记录进行合并,即将相同索引的数值进行求和运算,输出按照key值升序进行输出。
输入:
4
0 1
0 2
1 2
3 4
输出:
0 3
1 2
3 4
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct record{
int index;
int num;
};
int main(){
int len,i=0;
cin>>len;
vector<record> R(len);
while(i<len){
cin>>R[i].index>>R[i].num;
i++;
}
if(len==0){
cout<<endl;
return 0;
}
if(len==1){
cout<<R[len-1].index<<" "<<R[len-1].num<<endl;
return 0;
}
sort(R.begin(),R.end(),[](const record&a,const record&b)->bool{
if(a.index!=b.index) return a.index<=b.index;
else return a.num<b.num;
});
for(int i=1;i<len;i++){
int same_index_total=R[i-1].num;
while(R[i].index==R[i-1].index&&i<len){
same_index_total+=R[i].num;
i++;
}
cout<<R[i-1].index<<" "<<same_index_total<<endl;
}
//当最后一个元素所以不等于倒数第二个元素索引时的处理
//相等的情况已经在循环中处理了
if(R[len-1].index!=R[len-2].index) cout<<R[len-1].index<<" "<<R[len-1].num<<endl;
return 0;
}
10、输入一个int型整数,按照从右向左的阅读顺序,返回一个不含重复数字的新的整数。
输入:9876673 输出:37689
收获:
map是STL的一个关联容器,它提供一对一的hash。
第一个称为关键字(key),每个关键字只能在map中出现一次;
第二个称为该关键字的值(value)。
插入关键字可以直接 Map[character]++;
查询map中某个关键字是否存在Map.count(character);等于0则不存在,等于1则存在
#include<iostream>
#include<map>
using namespace std;
int main(){
int num;
cin>>num;
map<char,int> M;
while(num%10==0){
num/=10;
}
while(num>0){
//不重复则输出
if(!M.count(num%10)){
cout<<num%10;
M[num%10]++;
}
num/=10;
}
return 0;
}
11、编写一个函数,计算字符串中含有的不同字符的个数。字符在ACSII码范围内(0~127),换行表示结束符,不算在字符里。不在范围内的不作统计。多个相同的字符只计算一次。
收获:
#include<iostream>
#include<string>
#include<map>
using namespace std;
int main(){
string str;
getline(cin,str);
map<char,int> Map;
int real_size=0;
for(int i=0;i<str.size();i++){
if(!Map.count(str[i])) {
real_size++;
Map[str[i]]++;
}
}
cout<<real_size<<endl;
return 0;
}
12、将一个英文语句以单词为单位逆序排放。例如“I am a boy”,逆序排放后为“boy a am I”所有单词之间用一个空格隔开,语句中除了英文字母外,不再包含其他字符
收获:当主循环退出条件和i相关(判断下标是否越界),同时在主循环中的子循环退出条件也和i相关的时候,要注意子循环中也要判断i是否越界。
#include<iostream>
#include<string>
using namespace std;
int main(){
string str;
string temp;
getline(cin,str);
int i=str.size()-1;
while(i>=0){
int len=0;
while(str[i]!=' '&&i>=0){
len++;
i--;
}
temp+=(str.substr(i+1,len)+' ');
i--;
}
cout<<temp<<endl;
return 0;
}
13、密码要求:1.长度超过8位; 2.包括大小写字母.数字.其它符号,以上四种至少三种;3.不能有相同长度大于2的子串重复
收获:可以将重复功能的代码分离出一个函数;同时在最后判断三个条件的时候,若不符合可以列出子条件,这样的话有一个条件不符合就可以提前退出判断,减少运行时间,同时在
#include<iostream>
#include<string>
using namespace std;
string Password_Vertification(string str) {
int len=str.size();
int tag[4] = { 0 };
for (int i = 0; i < len; i++) {
if (str[i]>='A'&&str[i]<='Z') tag[0] = 1;
else if (str[i]>='a'&&str[i]<='z') tag[1] = 1;
else if (str[i]>='0'&&str[i]<='9') tag[2] = 1;
else tag[3] = 1;
//若增加这一句的话会超出运行时间,因为每次都要计算一下tag种元素的总和
//if (tag[0] + tag[1] + tag[2] + tag[3] >= 3) break;
}
bool flag = false;
for (int i = 0; i <= len - 6; i++) {
for (int j = i + 3; j <= len-3; j++) {
if (str[i] == str[j] && str[i + 1] == str[j + 1] && str[i + 2] == str[j + 2]) {
flag = true;
break;
}
}
if (flag == true) break;
}
if (len >= 9 && (tag[0] + tag[1] + tag[2] + tag[3] >= 3) && flag == false) return "OK";
else if (len <= 8 || (tag[0] + tag[1] + tag[2] + tag[3] <= 2) || flag == true) return "NG";
}
int main() {
string str;
while (getline(cin, str)) {
cout << Password_Vertification(str) << endl;
}
return 0;
}
14、实现删除字符串中出现次数最少的字符,若多个字符出现次数一样,则都删除。输出删除这些单词后的字符串,字符串中其它字符保持原来的顺序。注意每个输入文件有多组输入,即多个字符串用回车隔开
输入描述:字符串只包含小写英文字母, 不考虑非法输入,输入的字符串长度小于等于20个字节。
收获:当已知输入的字符数量范围或字母的范围可以考虑用空间换时间。
#include<iostream>
#include<string>
using namespace std;
string Del_str(string str){
string temp;
int a[26]={0};
int len=str.size();
int min=str.size();
for(int i=0;i<len;i++){
a[str[i]-'a']+=1;
}
for(int i=0;i<26;i++){
if((a[i]<=min)&&(a[i]!=0)){min=a[i];}
}
for(int i=0;i<len;i++){
if(a[str[i]-'a']>min){
temp+=str[i];
}
}
return temp;
}
int main() {
string str;
while(cin>>str){
cout<<Del_str(str)<<endl;
}
return 0;
}