HJ2 计算字符个数
题解看到一个比较新颖的解法:
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s;
getline(cin, s);
char c = tolower(getchar());
cout << count_if(s.begin(), s.end(), [c](char i) { return towlower(i) == c; }) << endl;
}
敲黑板:
-
- 没有用过count_if()算法
-
- 第三个参数没有看懂,是lambda表达式?
count_if函数用法详解
lambda表达式
常函数
HJ3明明的随机数
方法1:使用数组
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int main()
{
int n;
while(cin>>n)
{
int a;
int count[501]={0};
for(int i=0;i<n;i++)
{
cin>>a;
count[a]=1;
}
for(int i=0;i<501;i++)
{
if(count[i]==1)
cout<<i<<endl;
}
}
return 0;
}
方法2:使用容器set
set容器可以自动实现去重和排序
#include <iostream>
#include <set>
using std::cin;
using std::cout;
using std::endl;
using std::set;
int main()
{
int n;
while(cin>>n)
{
int a;
set<int> mset;
for(int i=0;i<n;i++)
{
cin>>a;
mset.insert(a);
}
set<int>::iterator it;
for(it = mset.begin();it!=mset.end();it++)
{
cout<<*it<<endl;
}
}
return 0;
}
思考:为什么使用set而不是unordered_set?
unordered_set底层使用hash表实现,查找效率更高,查找时间负载读O(1)。
set底层实现是红黑树,对于频繁插入和删除的情形更适合,时间复杂度O(logN)。
此处需要插入n个元素,对于需要频繁插入的情形,使用set比unordered_set效率更高。
方法3:使用容器vector+算法
unique()是C++标准库函数里面的函数,其功能是去除相邻的重复元素(只保留一个),所以使用前需要对数组进行排序。
C++ Unique函数 详细
#include <iostream>
#include <vector>
#include <algorithm>
using std::cin;
using std::cout;
using std::endl;
using std::vector;
int main()
{
int n;
while(cin>>n)
{
int a;
vector<int> mvec;
for(int i=0;i<n;i++)
{
cin>>a;
mvec.push_back(a);
}
sort(mvec.begin(),mvec.end());
auto tmp=unique(mvec.begin(),mvec.end());
mvec.erase(tmp,mvec.end());
vector<int>::iterator it;
for(it = mvec.begin();it!=mvec.end();it++)
{
cout<<*it<<endl;
}
}
return 0;
}
HJ4 字符串分隔
2022.01.16
方法1:string的substr函数
代码:
#include <iostream>
#include <string>
using std::string;
using std::cout;
using std::cin;
using std::endl;
void Parse(string str)
{
int len = str.size();
if(len>8)
{
string ms=str.substr(0,8);
cout<<ms<<endl;
Parse(str.substr(8,len-8));
}else {
int k = 8-len;
for(int i=0;i<k;i++)
{
str += '0';
}
cout<<str<<endl;
}
}
int main() {
string str;
while(cin>>str){
Parse(str);
}
}
// 64 位输出请用 printf("%lld")
方法2:
#include <string>
#include <iostream>
using std::string;
using std::cin;
using std::cout;
using std::endl;
int main()
{
string str;
while(getline(cin,str))
{
int len=str.size();
if(len%8!=0)
{
int k=8-len%8;
str.append(k,'0');
}
// for(int i=0;i<k;i++)
// {
// str+='0';
//}
len = str.size();
for(int i=0;i<len;i+=8)
{
cout<<str.substr(i,8)<<endl;
}
}
return 0;
}
方法3:
cout的成员函数width()设置输出的宽度
cout的成员函数fill设置输出宽度不够时,填充字符’0’
流操作符left指定左对齐
#include <string>
#include <iostream>
using std::string;
using std::cin;
using std::cout;
using std::endl;
using std::left;
int main()
{
string str;
while(getline(cin,str))
{
int len = str.size();
for(int i=0;i<len;i+=8)
{
cout.width(8);
cout.fill('0');
cout<<left<<str.substr(i,8)<<endl;
}
}
return 0;
}
HJ8 合并表记录
方法1
#include <iostream>
#include <map>
using namespace std;
int main() {
int n;
while (cin >> n) { // 注意 while 处理多个 case
int key,value;
map<int,int> mmap;
for(int i=0;i<n;i++)
{
cin>>key>>value;
mmap[key]+=value;
}
for(auto it=mmap.begin();it!=mmap.end();it++)
{
cout<<it->first<<" "<<it->second<<endl;
}
}
}
方法2
#include <iostream>
#include <map>
using namespace std;
int main() {
int n;
while (cin >> n) { // 注意 while 处理多个 case
int key,value;
map<int,int> mmap;
map<int,int>::iterator tmp;
for(int i=0;i<n;i++)
{
cin>>key>>value;
tmp = mmap.find(key);
if(tmp!=mmap.end())
{
mmap[key]=tmp->second+value;
}else{
mmap[key]=value;
}
}
for(auto it=mmap.begin();it!=mmap.end();it++)
{
cout<<it->first<<" "<<it->second<<endl;
}
}
}
思考:方法1和2中的两种map用法哪个更好
map可以用key做下标,map的下标运算符[ ]将关键码作为下标去执行查找,如果关键码不存在,则插入一个具有该关键码和mapped_type类型默认值的元素至map中,因此下标运算符[ ]在map应用中需要慎用。
const_map不能用,只希望确定某一个关键值是否存在而不希望插入元素时也不应该使用,mapped_type类型没有默认值也不应该使用。
如果find能解决需要,尽可能用find。
因此:
应该上面的两个方法中,方法2更推荐,更安全。
HJ9 提取不重复的数字
方法一:使用vector
#include <iostream>
#include <vector>
using namespace std;
int main() {
int num;
while (cin >> num) { // 注意 while 处理多个 case
int a;
int stat[10]={0};
vector<int> mv;
while(num>0)
{
a=num%10;
stat[a]++;
if(stat[a]==1)
{
mv.push_back(a);
}
num = num/10;
}
for(auto it=mv.begin();it!=mv.end();it++)
cout<<*it;
cout<<endl;
}
}
// 64 位输出请用 printf("%lld")
方法二:使用unordered_set
#include <iostream>
#include <algorithm>
#include <unordered_set>
using namespace std;
int main() {
int num;
while (cin >> num) { // 注意 while 处理多个 case
string str=to_string(num);
reverse(str.begin(),str.end());
unordered_set<char> mset;
string res;
for(char c:str)
{
if(mset.count(c)!=1)
{
res+=c;
mset.insert(c);
}
}
cout<<stoi(res)<<endl;
}
}
HJ13 句子逆序
描述
将一个英文语句以单词为单位逆序排放。例如“I am a boy”,逆序排放后为“boy a am I”
所有单词之间用一个空格隔开,语句中除了英文字母外,不再包含其他字符
方法1:string的方向迭代器string::const_reverse_iterator
#include <iostream>
#include <vector>
using namespace std;
int main()
{
string str;
while(getline(cin,str))
{
string tmp;
vector<string> mv;
for(string::const_reverse_iterator it=str.rbegin();it!=str.rend();it++)
{
if(*it==' ')
{
mv.push_back(tmp);
tmp="";
}else{
tmp=*it+tmp;
}
}
mv.push_back(tmp);
for(auto it=mv.begin();it!=mv.end();it++)
{
cout<<*it<<' ';
}
}
return 0;
}
方法2:stringstream
对于分隔符是空格,不要用stringstream方法,解析不对
在这里插入代码片
HJ17 坐标移动
方法1 string的substr
#include <iostream>
#include <vector>
using namespace std;
void helper(string mstr)
{
int x=0,y=0;
string tmp;
vector<string> mv;
for(int i=0;i<mstr.size();i++)
{
int strlen=0;
while(mstr[i]!=';')
{
strlen++;
i++;
}
mv.push_back(mstr.substr(i-strlen,strlen));
}
for(int i=0;i<mv.size();i++)
{
int num=0;
if(mv[i].size()==3&&isdigit(mv[i][1])&&isdigit(mv[i][2]))
{
num=(mv[i][1]-'0')*10+mv[i][2]-'0';
}
if(mv[i].size()==2&&isdigit(mv[i][1]))
{
num=mv[i][1]-'0';
}
switch(mv[i][0])
{
case 'A':
x=x-num;
break;
case 'S':
y=y-num;
break;
case 'W':
y=y+num;
break;
case 'D':
x=x+num;
break;
}
}
cout<<x<<','<<y<<endl;
}
int main()
{
string mstr;
while(cin>>mstr)
{
helper(mstr);
}
return 0;
}
方法2 stringstream
#include <iostream>
#include <sstream>
#include <vector>
using namespace std;
void helper1(string mstr)
{
int x=0,y=0;
stringstream ss(mstr);
string tmp;
vector<string> mv;
while(getline(ss,tmp,';'))
{
mv.push_back(tmp);
}
for(int i=0;i<mv.size();i++)
{
int num=0;
if(mv[i].size()==3&&isdigit(mv[i][1])&&isdigit(mv[i][2]))
{
num=(mv[i][1]-'0')*10+mv[i][2]-'0';
}
if(mv[i].size()==2&&isdigit(mv[i][1]))
{
num=mv[i][1]-'0';
}
switch(mv[i][0])
{
case 'A':
x=x-num;
break;
case 'S':
y=y-num;
break;
case 'W':
y=y+num;
break;
case 'D':
x=x+num;
break;
}
}
cout<<x<<','<<y<<endl;
}
int main()
{
string mstr;
while(cin>>mstr)
{
helper(mstr);
}
return 0;
}
思考:为什么使用unordered_set而不是set?
unordered_set底层使用hash表实现,查找效率更高,查找时间负载读O(1)。
set底层实现是红黑树,对于频繁插入和删除的情形更适合,时间复杂度O(logN)。
此处mset.count©查找是否包含字符c,使用unordered_set效率更高。
HJ3明明的随机数
其中的方法使用的是set,这两个场景有什么不同?
HJ3明明的随机数需要插入n个元素所以使用set效率更高。
HJ28 素数伴侣
代码还是有些地方不懂
#include <iostream>
#include <vector>
#include <string.h>
using namespace std;
vector<int> G[105];
int used[105];
int pre[105];
bool dfs(int k)
{
for (int i = 0; i < G[k].size(); i++)
{
if (used[G[k][i]] == 0)
{
used[G[k][i]] = 1;
//此处为什么要调用dfs??
if (pre[G[k][i]] == 0 || dfs(pre[G[k][i]]))
{
pre[G[k][i]] = k;
return true;
}
}
}
return false;
}
int main() {
//输入的数据大小满足 2≤val≤30000 ,两数之和小于80000
int isPrime[80000];
memset(isPrime, 0, sizeof(isPrime));
int i, j;
for (i = 2; i < 80000; i++)
{
for (j = 2; j<i; j++)
{
if (i%j == 0 || j*j>i)
break;
}
if (j*j > i)
isPrime[i] = 1;
}
int n;
while (cin >> n) { // 注意 while 处理多个 case
int nums[105];
//注意此处是i从1开始的,因为pre[]、used[]初值为0
for (int i = 1; i <= n; i++)
{
cin >> nums[i];
}
//注意此处是i从1开始的,因为pre[]、used[]初值为0
for (int i = 1; i <= n; i++)
{
for (int j = i + 1; j <= n; j++)
{
if (isPrime[nums[i] + nums[j]])
{
if (nums[i] % 2 == 1)
{
G[i].push_back(j);
}
else
{
G[j].push_back(i);
}
}
}
}
int count = 0;
memset(pre, 0, sizeof(pre));
//注意此处是i从1开始的,因为pre[]、used[]初值为0
for (int k = 1; k <= n; k++)
{
memset(used, 0, sizeof(used));
if (dfs(k))
{
count++;
}
}
cout << count << endl;
for (int i = 0; i < 105; i++)
{
G[i].clear();
}
}
}
// 64 位输出请用 printf("%lld")
知识点
math.h与algorithm
math.h 是常用的数学库。例如 开平方,取绝对值,计算三角函数。
Algorithms 是Template库,处理某范围元素的函数,例如 for_each (对每个做…), count (统计出现的个数),partition (分两部分)。
万能头文件
#include <bits/stdc++.h>