牛客每日一题
1. HJ1 字符串最后一个单词的长度
字符串
答题技巧:cin输入的机制,有空格会停止,系统把空格作为数据间的分隔符,整个英文句子会一个单词一个单词的读。非常巧妙的使用了cin的读取逻辑。
#include <iostream>
#include <string>
using namespace std;
int main(){
string s;
while(cin>>s);
cout<<s.size();
return 0;
}
好巧妙!!!
2. HJ2 计算某字符出现次数
#include<iostream>
#include<string>
using namespace std;
int main(){
string str;
char ch;
int count=0;
getline(cin, str);
cin>>ch;
char res=tolower(ch);
for(int i=0;i<str.size();i++){
if(tolower(str[i])==res){
count++;
}
}
cout<<count;
return 0;
}
一开始用cin输入字符串str,但是当字符串中有空格的时候,就会停止读取,答案错误,
所以改用了getline(),可以读取空格,答案正确。
3. HJ3 明明的随机数
题目描述
明明生成了NN个1到500之间的随机整数。请你删去其中重复的数字,即相同的数字只保留一个,把其余相同的数去掉,然后再把这些数从小到大排序,按照排好的顺序输出。
数据范围: 1 \le n \le 1000 \1≤n≤1000 ,输入的数字大小满足 1 \le val \le 500 \1≤val≤500
输入描述:
第一行先输入随机整数的个数 N 。 接下来的 N 行每行输入一个整数,代表明明生成的随机数。 具体格式可以参考下面的"示例"。
输出描述:
输出多行,表示输入数据处理后的结果
示例1
输入:
3
2
2
1
复制
输出:
1
2
复制
说明:
输入解释:
第一个数字是3,也即这个小样例的N=3,说明用计算机生成了3个1到500之间的随机整数,接下来每行一个随机数字,共3行,也即这3个随机数字为:
2
2
1
所以样例的输出为:
1
2
解法1:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
int a,b;
cin>>a;
vector<int> str;
for(int i=0;i<a;i++){
cin>>b;
str.push_back(b);
}
sort(str.begin(),str.end());
auto new_start=unique(str.begin(),str.end());
str.erase(new_start, str.end());
for(auto num:str){
cout<<num<<endl;
}
return 0;
}
知识点
unique函数
unique函数属于STL中比较常用函数,它的功能是元素去重。即”删除”序列中所有相邻的重复元素(只保留一个)。此处的删除,并不是真的删除,而是指重复元素的位置被不重复的元素给占领了(详细情况,下面会讲)。由于它”删除”的是相邻的重复元素,所以在使用unique函数之前,一般都会将目标序列进行排序。
二.函数原型
unique函数的函数原型如下:
1.只有两个参数,且参数类型都是迭代器:
iterator unique(iterator it_1,iterator it_2);
这种类型的unique函数是我们最常用的形式。其中这两个参数表示对容器中[it_1,it_2)范围的元素进行去重(注:区间是前闭后开,即不包含it_2所指的元素),返回值是一个迭代器,它指向的是去重后容器中不重复序列的最后一个元素的下一个元素。
unique函数的去重过程实际上就是不停的把后面不重复的元素移到前面来,也可以说是用不重复的元素占领重复元素的位置。
2.unique函数通常和erase函数一起使用,来达到删除重复元素的目的。(注:此处的删除是真正的删除,即从容器中去除重复的元素,容器的长度也发生了变换;而单纯的使用unique函数的话,容器的长度并没有发生变化,只是元素的位置发生了变化)关于erase函数的用法,可以参考:http://www.cnblogs.com/wangkundentisy/p/9023977.html。
erase函数:删除容器中从pos位置开始的n个元素。返回值是经过删除操作后的容器。
下面是一个具体的实例:
#include<iostream>
#include<algorithm>
#include<cassert>
using namespace std;
int main()
{
vector<int> a ={1,3,3,4,5,6,6,7};
vector<int>::iterator it_1 = a.begin();
vector<int>::iterator it_2 = a.end();
vector<int>::iterator new_end;
new_end = unique(it_1,it_2); //注意unique的返回值
a.erase(new_end,it_2);
cout<<"删除重复元素后的 a : ";
for(int i = 0 ; i < a.size(); i++)
cout<<a[i];
cout<<endl;
}
这里,他的返回值是去重后序列(这个序列不含有重复数值)的末尾的下一个元素,在上边代码中,unique后,数组顺序为:1,3,4,5,6,7,X(代表重复数字,具体哪个不重要),X。他的返回值就是第一个重复数字的地址,所以,能用erase 实现彻底去重。
最后输出结果:
134567
解法2:
#include<iostream>
#include<set>
#include<algorithm>
using namespace std;
int main(){
int n,a;
cin>>n;
set<int>nums;
for(int i=0;i<n;i++){
cin>>a;
nums.insert(a);
}
for(auto num:nums){
cout<<num<<endl;
}
return 0;
}
知识点
set
set就是集合,STL的set用二叉树实现,集合中的每个元素只出现一次(参照数学中集合的互斥性),并且是排好序的(默认按键值升序排列),访问元素的时间复杂度是O ( log 2 n )。
for (auto x : nums)的作用:
相当于:
for (vector< int >::iterator iter = nums.begin(); iter != nums.end(); iter++)
for(auto a:b)中b为一个容器,效果是利用a遍历并获得b容器中的每一个值,但是a无法影响到b容器中的元素。
for(auto &a:b)中加了引用符号,可以对容器中的内容进行赋值,即可通过对a赋值来做到容器b的内容填充。
4. HJ4 字符串分隔
题目
描述
•输入一个字符串,请按长度为8拆分每个输入字符串并进行输出;
•长度不是8整数倍的字符串请在后面补数字0,空字符串不处理。
输入描述:
连续输入字符串(每个字符串长度小于等于100)
输出描述:
依次输出所有分割后的长度为8的新字符串
示例1
输入:
abc
复制
输出:
abc00000
复制
#include <string>
#include<iostream>
#include <vector>
using namespace std;
int main() {
string str;
while(cin>>str){
int len=str.size();
if(len%8!=0){
int less=8-len%8;
str.append(less,'0');
}
int newLen=str.size();
for(int j=0;j<newLen;j+=8){
cout<<str.substr(j,8)<<endl;
}
}
return 0;
}
substr(a,b):第一个参数a是要截取的字符串的起始位置,后一个参数b是要截取字符串的长度。
5. HJ5进制转换
描述
写出一个程序,接受一个十六进制的数,输出该数值的十进制表示。
数据范围:保证结果在 1 \le n \le 2^{31}-1 \1≤n≤2
31
−1
输入描述:
输入一个十六进制的数值字符串。
输出描述:
输出该数值的十进制字符串。不同组的测试用例用\n隔开。
示例1
输入:
0xAA
复制
输出:
170
复制
C语言中 %d 与 %i 的区别 和注意事项
在 printf 格式串中使用时,没有区别,输出都是十进制。
在 scanf 格式串中使用时,有点区别,如下:
——在scanf格式中,%d 只与十进制形式的整数相匹配。
——而%i 则可以匹配八进制、十进制、十六进制表示的整数。·
——例如: 如果输入的数字有前缀 0(018、025),%i将会把它当作八进制数来处理,如果有前缀0x (0x54),它将以十六进制来处理。
6. HJ6 质数因子
描述
功能:输入一个正整数,按照从小到大的顺序输出它的所有质因子(重复的也要列举)(如180的质因子为2 2 3 3 5 )
数据范围: 1 \le n \le 2 \times 10^{9} + 14 \1≤n≤2×10
9
+14
输入描述:
输入一个整数
输出描述:
按照从小到大的顺序输出它的所有质数的因子,以空格隔开。
示例1
输入:
180
输出:
2 2 3 3 5
注意:该道题目比较简单,但是很容易超时,所以要找到合适的算法策略,结束条件是1=x/x。
#include<iostream>
#include <math.h>
using namespace std;
int main(){
int num=0;
cin>>num;
int flag=num;
if(flag==1){
cout<<flag;
return 0;
}
for(int i=2;i<=sqrt(flag);i++){
if(flag%i==0){
flag/=i;
cout<<i<<" ";
i=1;
}
}
cout<<flag<<" ";
return 0;
}
7. HJ7 取近似值
描述
写出一个程序,接受一个正浮点数值,输出该数值的近似整数值。如果小数点后数值大于等于 0.5 ,向上取整;小于 0.5 ,则向下取整。
数据范围:保证输入的数字在 32 位浮点数范围内
输入描述:
输入一个正浮点数值
输出描述:
输出该数值的近似整数值
示例1
输入:
5.5
复制
输出:
6
复制
说明:
0.5>=0.5,所以5.5需要向上取整为6
示例2
输入:
2.499
复制
输出:
2
复制
说明:
0.499<0.5,2.499向下取整为2
具体做法:
利用C++自带的强制类型转化可以将float转换成int,但是默认是向下取整,因此我们要给数字加上0.5,因为如果它原本小数部分小于0.5,加上0.5向下取整也是四舍,但是如果它原本小数部分大于等于0.5,加上0.5以后向下取整就是五入了。
解题
#include <iostream>
using namespace std;
int main(){
double num;
cin>>num;
cout<<(int)(num+0.5);
return 0;
}
8.HJ8 合并表记录
描述
数据表记录包含表索引index和数值value(int范围的正整数),请对表索引相同的记录进行合并,即将相同索引的数值进行求和运算,输出按照index值升序进行输出。
提示:
0 <= index <= 11111111
1 <= value <= 100000
输入描述:
先输入键值对的个数n(1 <= n <= 500)
接下来n行每行输入成对的index和value值,以空格隔开
输出描述:
输出合并后的键值对(多行)
示例1
输入:
4
0 1
0 2
1 2
3 4
复制
输出:
0 3
1 2
3 4
复制
示例2
输入:
3
0 1
0 2
8 9
复制
输出:
0 3
8 9
解题
#include<iostream>
#include<map>
using namespace std;
int main(){
int n;
cin>>n;
map<int,int>m;
map<int,int>::iterator it;
for(int i=0;i<n;i++){
int k,v;
cin>>k>>v;
it=m.find(k);
if(it!=m.end()){
m[k]=it->second+v;
}else{
m[k]=v;
}
}
for(it=m.begin();it!=m.end();it++){
cout<<it->first<<" "<<it->second<<endl;;
}
return 0;
}
知识点回顾:
-
Map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据 处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道。这里说下map内部数据的组织,map内部自建一颗红黑树(一 种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的,后边我们会见识到有序的好处。
-
C++中map.find()函数
函数原型:
iterator find (const key_type& k);
const_iterator find (const key_type& k) const;
函数作用:
在容器中寻找值为k的元素,返回该元素的迭代器。否则,返回map.end()。
9.HJ9 提取不重复的整数
校招时部分企业笔试将禁止编程题跳出页面,为提前适应,练习时请使用在线自测,而非本地IDE。
描述
输入一个 int 型整数,按照从右向左的阅读顺序,返回一个不含重复数字的新的整数。
保证输入的整数最后一位不是 0 。
数据范围: 1 \le n \le 10^{8} \1≤n≤108
输入描述:
输入一个int型整数
输出描述:
按照从右向左的阅读顺序,返回一个不含重复数字的新的整数
示例1
输入:
9876673
输出:
37689
解法:哈希表
#include<stdio.h>
int main(){
int num,n;
int hash[10]={0};
scanf("%d",&n);
while(n>0){
num=n%10;
n/=10;
if(hash[num]==0){
hash[num]=1;
printf("%d",num);
}
}
return 0;
}
#include<iostream>
#include<string>
#include<set>
using namespace std;
int main(){
string str;
set<char>s;
int i=0;
cin>>str;
while(i<str.size()){
s.insert(str[i]);
i++;
}
cout<<s.size();
return 0;
}
10.HJ10 字符个数统计
描述
编写一个函数,计算字符串中含有的不同字符的个数。字符在 ASCII 码范围内( 0~127 ,包括 0 和 127 ),换行表示结束符,不算在字符里。不在范围内的不作统计。多个相同的字符只计算一次
例如,对于字符串 abaca 而言,有 a、b、c 三种不同的字符,因此输出 3 。
数据范围: 1 \le n \le 500 \1≤n≤500
输入描述:
输入一行没有空格的字符串。
输出描述:
输出 输入字符串 中范围在(0~127,包括0和127)字符的种数。
示例1
输入:
abc
输出:
3
示例2
输入:
aaa
输出:
1
方法1:哈希表
#include<stdio.h>
int main(){
int hash[128]={0};
char str[501];
int i=0,count=0;
gets(str);
int len=strlen(str);
for(int i=0;i<len;i++){
int index=((int)str[i]);
if(hash[index]==0){
hash[index]=((int)str[i]);
count++;
}
}
printf("%d",count);
return 0;
}
方法2:set
#include<iostream>
#include<string>
#include<set>
using namespace std;
int main(){
string str;
set<char>s;
int i=0;
cin>>str;
while(i<str.size()){
s.insert(str[i]);
i++;
}
cout<<s.size();
return 0;
}
11、12题很简单,不做记录了。
13HJ13 句子逆序
描述
将一个英文语句以单词为单位逆序排放。例如“I am a boy”,逆序排放后为“boy a am I”
所有单词之间用一个空格隔开,语句中除了英文字母外,不再包含其他字符
数据范围:输入的字符串长度满足 1 \le n \le 1000 \1≤n≤1000
注意本题有多组输入
输入描述:
输入一个英文语句,每个单词用空格隔开。保证输入只包含空格和字母。
输出描述:
得到逆序的句子
示例1
输入:
I am a boy
输出:
boy a am I
示例2
输入:
nowcoder
输出:
nowcoder
解题:巧妙哭了呜呜呜
#include<iostream>
#include<string>
using namespace std;
int main(){
string str;
string ans;
while(cin>>str){
ans=str+" "+ans;
}
cout<<ans;
return 0;
}