1.字符串翻转函数
string s;
reverse(s.begin(),s.end());
2.不区分大小写统计字符出现的个数
需要判断是大小写字母。根据ASCII码值,大写字母+32==小写字母
void func(string s,char ch)
{
int len=s.length(),cnt=0;
if(ch>64)
{
for(int i=0;i<len;i++)
{
if(s[i]+32==ch||s[i]==ch||s[i]-32==ch)cnt++;
}
}
else
{
for(int i=0;i<len;i++)
{
if(s[i]==ch)cnt++;
}
}
cout<<cnt<<endl;
}
3.字符串分割
描述
•输入一个字符串,请按长度为8拆分每个输入字符串并进行输出;
•长度不是8整数倍的字符串请在后面补数字0,空字符串不处理。
示例
输入:abc
输出:abc00000
#include<bits/stdc++.h>
using namespace std;
int main() {
string s;
while(cin>>s)
{
//补0
int len=s.size();
if(len%8!=0)
{
int count=8-len%8;
s.append(count,'0');
}
//按格式输出
int lenNew=s.size();
for(int i=0;i<lenNew;i+=8)
{
cout<<s.substr(i,8)<<endl;
}
}
}
补充 string::append
string str1 = "hello";
string str2 = "the";
string str3 = "world";
char* chs1 = "come-on.";
str1.append(str2);
str1 += str3;
str1.append("lusx.");
str1 += chs1;
cout << str1 << endl;//输出:hellotheworldlusx.(字符串之间没有空格符)
//2.在字符串的的末尾添加str字符串中索引为(index, index+n)的子串
string str4;
string str5 = "six-six-six...";
char* chs2 = "lue-lue-lue...";
cout << str4.append(chs2, 4, 3) << endl;//输出:lue
string str6;
cout << str6.append(str5, 4, 3) << endl;//输出:six
string str6_1;
cout << str6_1.append(str5, 4) << endl;//six-six
//3.在字符串str后面添加char字符串的前n个字符
string str7,str8;
char* chs3 = "h-e-l-l-o";
cout << str7.append(chs3, 1) << endl;//输出:h
cout << str8.append("h-e-l-l-o", 1) << endl;输出:h
//4.在字符串str的末尾添加n个字符c
string str9;
str9 = string(chs3);
cout << str9.append(3, '!') << endl;
string str = "01234567"
string s1 = str.substr(2, 3);//s1 = "234" 从下标2开始截取长度为3的子串
string s2 = str.substr(6, 3);//s2 = "67" 从下标6开始截取,但由于超出了str,故子串一直延续到str结尾
string s3 = str.sbustr(5);//s3 = "567" 未指定长度,一直延续到str的结尾
查找多个匹配的字符位置
while(str.find(ch, p)!=string::npos){
p = str.find(ch, p);//返回下标
cout<<p<<endl;
p = p + 1;//从后面位置继续匹配
}
string str="abcdefab";
str.find(“ab”,1);//从下标1开始正向查找、正向匹配,所以结果为6。
str.find(“ab”);//如果没有第二个参数,默认第二个参数为0,结果为0
str.rfind(“fab”,4);//从下标为4开始逆向查找,正向匹配,结果找不到,返回npos。
str.find(“fab”);//如果没有第二个参数,默认从下标npos开始。npos定义为保证大于任何有效下标的值。结果为5。
4.进制转换
输入十六进制,输出10进制整数
示例(0x表示十六进制)
输入:0xAA
输出:170
int main(){
int num;
while(cin>>hex>>num)
{
cout<<num<<endl;
}
}
4.质数因子
输入:180
输出:2 2 3 3 5
#include <bits/stdc++.h>
using namespace std;
void func(int n)
{
for(int i=2;i<=sqrt(n)&&i<=n;i++)
{
while(n%i==0){
cout<<i<<" ";
n/=i;
}
}
if(n-1)cout<<n<<" ";
}
int main() {
int n;
cin>>n;
func(n);
}
5.取近似值
using namespace std;
int main() {
float a;
cin>>a;
cout<<round(a);//四舍五入
cout<<ceil(a);//向上取整
cout<<floor(a);//向下取整
}
6.合并表
输入:前面是下标,后面是值,相同下标的合并求和
4
0 1
0 2
1 2
3 4输出:
0 3
1 2
3 4
下面用数组来保存的方法是可以得到上面的示例结果的,但是如果示例下标过大就会出现段错误。
#include <bits/stdc++.h>
using namespace std;
#include <iostream>
using namespace std;
int main() {
long int n,a[100]={0};
cin>>n;
int flag[100]={0};
for(int i=0;i<n;i++)
{
int index,value;
cin>>index>>value;
a[index]+=value;
flag[index]=1;
}
for(int i=0;i<n;i++)
{
if(flag[i]==1)
cout<<i<<" "<<a[i]<<endl;
}
}
用map的方法
#include<iostream>
#include<map>
using namespace std;
int main() {
int n;
cin>>n; //输入键值对的个数
map<int, int> m; //使用map容器,自带键值对数据结构
map<int, int>::iterator it; //map类型的迭代器
for(int i=0;i<n;i++) {
int a,b;
cin>>a>>b; //每行输入一个键值对
it = m.find(a); //查找键a是否存在
if(it != m.end()) { //如果存在,对键相同的单元的值部分进行求和;
m[a] = it->second + b;
}else { //如果不存在生成新的键值对
m[a] = b;
}
}
for(it=m.begin();it!=m.end();it++) { //遍历打印
cout<<it->first<<" "<<it->second<<endl;
}
return 0;
}
补充:
map容器
存储唯一键值(键是唯一的,重复相同键元素只保持最后一次赋值操作) + 内部集合有序(内部元素对象按照键进行排序)
7.提取不重复整数
输入一个 int 型整数,按照从右向左的阅读顺序,返回一个不含重复数字的新的整数。
保证输入的整数最后一位不是 0 。
输入:9876673
输出:37689
#include <bits/stdc++.h>
using namespace std;
//依次取出末尾的数%10,可以用一个数组进行标记
int main() {
int x,a[10]={0},cnt=0;
cin>>x;
while(x)
{
int num=x%10;
a[num]+=1;
x=x/10;
if(a[num]==1)cout<<num;//第一次出现则输出
}
return 0;
}
8.统计字符个数
编写一个函数,计算字符串中含有的不同字符的个数。字符在 ASCII 码范围内( 0~127 ,包括 0 和 127 ),换行表示结束符,不算在字符里。不在范围内的不作统计。多个相同的字符只计算一次
例如,对于字符串 abaca 而言,有 a、b、c 三种不同的字符,因此输出 3 。
数据范围: 1≤�≤500 1≤n≤500
示例1:
输入:abc
输出:3
示例1:
输入:aaa
输出:1
方法一:使用set容器
#include <bits/stdc++.h>
using namespace std;
int main() {
string str;
getline(cin,str);
set<char>s;//使用set容器
for(int i=0;i<str.size();i++)
{
s.insert(str[i]);//将str中的字符逐个加到set容器中
}
cout<<s.size()<<endl;
return 0;
}
补充set容器
s.insert(2); //set只允许一个值出现一次,要插入相同元素请用multiset
set<int> s;
s.begin() 返回set容器的第一个元素
s.end() 返回set容器的最后一个元素
s.clear() 删除set容器中的所有的元素
s.empty() 判断set容器是否为空
s.insert() 插入一个元素
s.erase() 删除一个元素
s.size() 返回当前set容器中的元素个数
方法二、hash表
#include <bits/stdc++.h>
using namespace std;
#define MAX_TABLE 128
/*
运用的是HASH表的思想,因为只有最多只有128种数据,所以只需维护一个大小为128的字符数组,让输入的字符作为数组下标,取出这个下标数组中的字符直接与输入的字符比较(不用for循环从头再查),如果相同则跳过,不同则赋值,让结果++,最后遇到'\n'结束循环,返回结果即可。
*/
int main() {
char hash[MAX_TABLE]={-1};
char c=0;
int num=0;
while(cin>>c)
{
if(c=='\n')break;
if(hash[(int)c]!=c)
{
hash[(int)c]=c;
num++;
}
}
cout<<num<<endl;
}
补充ASCII码
9.数字颠倒
输入一个整数,将这个整数以字符串的形式逆序输出
程序不考虑负数的情况,若数字含有0,则逆序形式也含有0,如输入为100,则输出为001
数据范围: 0≤�≤230−1 0≤n≤230−1
示例1
输入:1516000
输出:0006151
示例2
输入:0
输出:0
#include <iostream>
using namespace std;
int main() {
long int x;
cin>>x;
if(x==0)cout<<0;
else{
while(x)
{
int num=x%10;
cout<<num;
x/=10;
}
}
return 0;
}
9.句子逆序
示例1
输入:I am a boy
输出:boy a am I
示例2
输入:nowcoder
输出:nowcoder
方法一、使用vector容器
#include <bits/stdc++.h>
using namespace std;
int main() {
string str;
vector<string>vec;
while(cin>>str)//cin是以空格为输入标志的,空格表示输入结束
{
vec.push_back(str);
}
for(int i=vec.size()-1;i>=0;i--)
cout<<vec[i]<<' ';
return 0;
}
方法二、直接进行连接
#include <bits/stdc++.h>
using namespace std;
int main() {
string str,res;
while(cin>>str)
{
str=str+" "+res;
res=str;
}
cout<<res<<endl;
}
补充:vector容器
vector相当于数组
vector和普通数组的区别:
1.数组是静态的,长度不可改变,而vector可以动态扩展,增加长度
2.数组内数据通常存储在栈上,而vector中数据存储在堆上
10.字符串排序
给定 n 个字符串,请对 n 个字符串按照字典序排列。
示例
输入:
9
cap
to
cat
card
two
too
up
boat
boot输出:
boat
boot
cap
card
cat
to
too
two
up
思路一、冒泡排序进行排序
利用string进行读入,string的字典序是可以通过<,>重载来实现的,那么我们本质就是利用一种排序算法来实现
- 比较相邻元素,前一个比后一个大(或者前一个比后一个小)就交换位置。
- 每一对相邻的元素进行重复的工作,从开始对一直到结尾对,这一步完成后,结尾为最大值或者是最小值
- 对所以的元素都进行上面的操作 下面是完整代码:
#include <bits/stdc++.h>
#include <vector>
using namespace std;
vector<string> q;
int main() {
int n;
cin>>n;
string s;
for(int i=0;i<n;i++)
{
cin>>s;
q.push_back(s);
}
//冒泡排序
for(int i=0;i<n;i++)
{
for(int j=1;j<n;j++)
{
if(q[j]<q[j-1])swap(q[j],q[j-1]);
}
}
for(int i=0;i<n;i++)
{
cout<<q[i]<<endl;
}
return 0;
}
思路二 利用库函数sort
#include <bits/stdc++.h>
#include <vector>
using namespace std;
vector<string> q;
int main() {
int n;
cin>>n;
string s;
for(int i=0;i<n;i++)
{
cin>>s;
q.push_back(s);
}
sort(q.begin(),q.end());//利用sort库函数进行排序
for(int i=0;i<n;i++)
cout<<q[i]<<endl;
return 0;
}
10.进制转换
描述
输入一个 int 型的正整数,计算出该 int 型数据在内存中存储时 1 的个数。
数据范围:保证在 32 位整型数字范围内
输入描述:
输入一个整数(int类型)
输出描述:
这个数转换成2进制后,输出1的个数
示例
输入:5
输出:2
#include <iostream>
using namespace std;
//
int main() {
int x,cnt=0;
cin>>x;
if(x==0)cout<<0<<endl;
else{
while(x)
{
int res=x%2;
if(res==1)cnt++;
x/=2;
}
}
cout<<cnt<<endl;
}
进一步简化代码
#include<iostream>
using namespace std;
int main()
{
int n;
cin>>n;
int m=0;
while(n)
{
m+=n%2;
n/=2;
}
cout<<m;
}
11.购物单
描述
王强决定把年终奖用于购物,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:
主件
附件
电脑
打印机,扫描仪
书柜
图书
书桌
台灯,文具
工作椅
无
如果要买归类为附件的物品,必须先买该附件所属的主件,且每件物品只能购买一次。
每个主件可以有 0 个、 1 个或 2 个附件。附件不再有从属于自己的附件。
王强查到了每件物品的价格(都是 10 元的整数倍),而他只有 N 元的预算。除此之外,他给每件物品规定了一个重要度,用整数 1 ~ 5 表示。他希望在花费不超过 N 元的前提下,使自己的满意度达到最大。
满意度是指所购买的每件物品的价格与重要度的乘积的总和,假设设第�i件物品的价格为�[�]v[i],重要度为�[�]w[i],共选中了�k件物品,编号依次为�1,�2,...,��j1,j2,...,jk,则满意度为:�[�1]∗�[�1]+�[�2]∗�[�2]+…+�[��]∗�[��]v[j1]∗w[j1]+v[j2]∗w[j2]+…+v[jk]∗w[jk]。(其中 * 为乘号)
请你帮助王强计算可获得的最大的满意度。
输入描述:
输入的第 1 行,为两个正整数N,m,用一个空格隔开:
(其中 N ( N<32000 )表示总钱数, m (m <60 )为可购买的物品的个数。)
从第 2 行到第 m+1 行,第 j 行给出了编号为 j-1 的物品的基本数据,每行有 3 个非负整数 v p q
(其中 v 表示该物品的价格( v<10000 ), p 表示该物品的重要度( 1 ~ 5 ), q 表示该物品是主件还是附件。如果 q=0 ,表示该物品为主件,如果 q>0 ,表示该物品为附件, q 是所属主件的编号)
输出描述:
输出一个正整数,为张强可以获得的最大的满意度。
输入:
1000 5 800 2 0 400 5 1 300 5 1 400 3 0 500 2 0 输出: 2200示例2
输入:
50 5 20 3 5 20 3 5 10 3 0 10 2 0 10 1 0输出:
130说明:
由第1行可知总钱数N为50以及希望购买的物品个数m为5; 第2和第3行的q为5,说明它们都是编号为5的物品的附件; 第4~6行的q都为0,说明它们都是主件,它们的编号依次为3~5; 所以物品的价格与重要度乘积的总和的最大值为10*1+20*3+20*3=130
先来看下经典的0-1背包问题,稍作修改可以得到本题的答案
0-1背包问题
问题描述:有一个背包可以装物品的总重量为W,现有N个物品,每个物品重w[i],价值v[i],用背包装物品,能装的最大价值是多少?
定义状态转移方程dp[i][j],表示前i个物品,背包重量为j的情况下能装的最大价值。
例如dp[3][4],表示用前3个物品装入重量为4的背包所能获得的最大价值是6,此时并不是3个物品全部装入,而是3个物品满足装入背包的条件下的最大价值。
状态转移方程:
dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i])
//表示当前物品装入或者不装入背包
1. 抽丝剥茧
看到题目的第一想法就是很像背包问题,如果不考虑“附件”的问题,那么就是0-1背包问题。
一开始觉得要考虑附件好像整个问题就会变得复杂,还挺头痛的。
但是所谓附件,表面上在制造问题,但是实际上也真的就是“附件”。2. 化繁为简
我们可以这样理解,对于同一个物品,现在它的价格、重要度都是可变的
那么我们只需要对每一个主件尝试如下四种情况:
- 仅加入一个主件;
- 加入主件和第一个附件;
- 加入主件和第二个附件;
- 加入主件和两个附件;
在以上四种情况中找到最大值就能回归到0-1背包问题。
抽象出来:
dp[i][j]=max(dp[i-1][j],{四种情况产生的价值})
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
int N, m; // N 奖金 m 物品个数
cin >> N >> m;
N /= 10; // 由于所有的价格都是10的整倍数,所以可以均除10以简化运算复杂度
int price, priority, hasAttachments;
// 使用一个(m+1)X6的数组存储数据,m+1是根据物品编号,0作废;6考虑可能有附件的最多的情况
vector<vector<int>> data(m+1, vector<int>(6, 0));
for(int i = 1; i <= m; i++){
cin >> price >> priority >> hasAttachments;
// 主件
if(hasAttachments == 0){
data[i][0] = price/10;
data[i][1] = priority;
}
// 第一个附件
else if(data[hasAttachments][2] == 0){
data[hasAttachments][2] = price/10;
data[hasAttachments][3] = priority;
}
// 第二个附件
else {
data[hasAttachments][4] = price/10;
data[hasAttachments][5] = priority;
}
}
vector<vector<int>> dp(m+1, vector<int>(N+1, 0));
for(int i = 1; i < m+1; i++){
for(int j = 1; j < N+1; j++){
int pricePrime = data[i][0];
int priceAtta1 = data[i][2];
int priceAtta2 = data[i][4];
int priorPrime = data[i][1];
int priorAtta1 = data[i][3];
int priorAtta2 = data[i][5];
dp[i][j] = j >= pricePrime ? max(dp[i-1][j - pricePrime]
+ priorPrime * pricePrime,
dp[i-1][j]) : dp[i-1][j];
dp[i][j] = j >= (pricePrime + priceAtta1) ? max(dp[i-1][j - pricePrime - priceAtta1]
+ priorPrime * pricePrime
+ priorAtta1 * priceAtta1,
dp[i][j]) : dp[i][j];
dp[i][j] = j >= (pricePrime + priceAtta2) ? max(dp[i-1][j - pricePrime - priceAtta2]
+ priorPrime * pricePrime
+ priorAtta2 * priceAtta2,
dp[i][j]) : dp[i][j];
dp[i][j] = j >= (pricePrime + priceAtta1 + priceAtta2) ?
max(dp[i-1][j - pricePrime - priceAtta1 - priceAtta2]
+ priorPrime * pricePrime
+ priorAtta1 * priceAtta1
+ priorAtta2 * priceAtta2,
dp[i][j]) : dp[i][j];
}
}
cout << dp[m][N] * 10 <<endl;
return 0;
}
12.坐标移动
描述
开发一个坐标计算工具, A表示向左移动,D表示向右移动,W表示向上移动,S表示向下移动。从(0,0)点开始移动,从输入字符串里面读取一些坐标,并将最终输入结果输出到输出文件里面。
输入:
合法坐标为A(或者D或者W或者S) + 数字(两位以内)
坐标之间以;分隔。
非法坐标点需要进行丢弃。如AA10; A1A; $%$; YAD; 等。
下面是一个简单的例子 如:
A10;S20;W10;D30;X;A1A;B10A11;;A10;
处理过程:
起点(0,0)
+ A10 = (-10,0)
+ S20 = (-10,-20)
+ W10 = (-10,-10)
+ D30 = (20,-10)
+ x = 无效
+ A1A = 无效
+ B10A11 = 无效
+ 一个空 不影响
+ A10 = (10,-10)
结果 (10, -10)
数据范围:每组输入的字符串长度满足 1≤�≤10000 1≤n≤10000 ,坐标保证满足 −231≤�,�≤231−1 −231≤x,y≤231−1 ,且数字部分仅含正数
输入描述:
一行字符串
输出描述:
最终坐标,以逗号分隔
示例1
输入:A10;S20;W10;D30;X;A1A;B10A11;;A10;
输出:10,-10
示例2
输入:ABC;AKL;DA1;
输出:0,0
本题思路不难,主要学习字符串的划分,以及如何访问到每一个字符串的每一位
#include <algorithm>
#include <bits/stdc++.h>
#include <csetjmp>
#include <iterator>
using namespace std;
int Move(string str)
{
int x=0,y=0;//初始化横纵坐标
int len=str.size();//获取字符串的总长度
vector<string>vec;//用一个向量来存储分割后的多个子字符串
//按';'进行分割
int sublen=0;
for(int i=0;i<len;i++)
{
if(str[i]!=';')
{
sublen++;
continue;
}
vec.push_back(str.substr(i-sublen,sublen));
sublen=0;
}
//坐标移动
for(int i=0;i<vec.size();i++)
{
int num=0;//横纵坐标移动的大小
//若字符串为三位有效位
if((vec[i].size()==3)&&(vec[i][1]>='0'&&vec[i][1]<='9')&&(vec[i][2]>='0'&&vec[i][2]<='9')) num=(vec[i][1]-'0')*10+(vec[i][2]-'0');
//若为两位有效位,则第二位是坐标移动的大小
if((vec[i].size()==2)&&(vec[i][1]>='0'&&vec[i][1]<='9'))
num=(vec[i][1]-'0');
//若为一位有效位,则坐标无移动
if(vec[i].size()==1)num=0;
//确定坐标方向
switch(vec[i][0])
{
case 'A':x-=num;
break;
case 'D':x+=num;
break;
case 'S':y-=num;
break;
case 'W':y+=num;
break;
default:
break;
}
}
cout<<x<<","<<y<<endl;
return 0;
}
int main() {
string str;
while(cin>>str)
{
Move(str);
}
return 0;
}
// 64 位输出请用 printf("%lld")
13.识别有效的IP地址和掩码并进行分类
请解析IP地址和对应的掩码,进行分类识别。要求按照A/B/C/D/E类地址归类,不合法的地址和掩码单独归类。
所有的IP地址划分为 A,B,C,D,E五类
A类地址从1.0.0.0到126.255.255.255;
B类地址从128.0.0.0到191.255.255.255;
C类地址从192.0.0.0到223.255.255.255;
D类地址从224.0.0.0到239.255.255.255;
E类地址从240.0.0.0到255.255.255.255
私网IP范围是:
从10.0.0.0到10.255.255.255
从172.16.0.0到172.31.255.255
从192.168.0.0到192.168.255.255
子网掩码为二进制下前面是连续的1,然后全是0。(例如:255.255.255.32就是一个非法的掩码)
(注意二进制下全是1或者全是0均为非法子网掩码)
注意:
1. 类似于【0.*.*.*】和【127.*.*.*】的IP地址不属于上述输入的任意一类,也不属于不合法ip地址,计数时请忽略
2. 私有IP地址和A,B,C,D,E类地址是不冲突的
输入描述:
多行字符串。每行一个IP地址和掩码,用~隔开。
请参考帖子https://www.nowcoder.com/discuss/276处理循环输入的问题。
输出描述:
统计A、B、C、D、E、错误IP地址或错误掩码、私有IP的个数,之间以空格隔开。
示例1
输入:
10.70.44.68~255.254.255.0
1.0.0.1~255.0.0.0
192.168.0.2~255.255.255.0
19..0.~255.255.255.0输出:
1 0 1 0 0 2 1
说明:
10.70.44.68~255.254.255.0的子网掩码非法,19..0.~255.255.255.0的IP地址非法,所以错误IP地址或错误掩码的计数为2;
1.0.0.1~255.0.0.0是无误的A类地址;
192.168.0.2~255.255.255.0是无误的C类地址且是私有IP;
所以最终的结果为1 0 1 0 0 2 1示例2
输入:
0.201.56.50~255.255.111.255 127.201.56.50~255.255.111.255输出:
0 0 0 0 0 0 0说明:
类似于【0.*.*.*】和【127.*.*.*】的IP地址不属于上述输入的任意一类,也不属于不合法ip地址,计数时请忽略
14.简单错误记录
描述
开发一个简单错误记录功能小模块,能够记录出错的代码所在的文件名称和行号。
处理:
1、 记录最多8条错误记录,循环记录,最后只用输出最后出现的八条错误记录。对相同的错误记录只记录一条,但是错误计数增加。最后一个斜杠后面的带后缀名的部分(保留最后16位)和行号完全匹配的记录才做算是“相同”的错误记录。
2、 超过16个字符的文件名称,只记录文件的最后有效16个字符;
3、 输入的文件可能带路径,记录文件名称不能带路径。也就是说,哪怕不同路径下的文件,如果它们的名字的后16个字符相同,也被视为相同的错误记录
4、循环记录时,只以第一次出现的顺序为准,后面重复的不会更新它的出现时间,仍以第一次为准
数据范围:错误记录数量满足 1≤n≤100 ,每条记录长度满足 1≤len≤100
输入描述:
每组只包含一个测试用例。一个测试用例包含一行或多行字符串。每行包括带路径文件名称,行号,以空格隔开。
输出描述:
将所有的记录统计并将结果输出,格式:文件名 代码行数 数目,一个空格隔开,如:
示例1
输入:
D:\zwtymj\xccb\ljj\cqzlyaszjvlsjmkwoqijggmybr 645 E:\je\rzuwnjvnuz 633 C:\km\tgjwpb\gy\atl 637 F:\weioj\hadd\connsh\rwyfvzsopsuiqjnr 647 E:\ns\mfwj\wqkoki\eez 648 D:\cfmwafhhgeyawnool 649 E:\czt\opwip\osnll\c 637 G:\nt\f 633 F:\fop\ywzqaop 631 F:\yay\jc\ywzqaop 631 D:\zwtymj\xccb\ljj\cqzlyaszjvlsjmkwoqijggmybr 645复制输出:
rzuwnjvnuz 633 1 atl 637 1 rwyfvzsopsuiqjnr 647 1 eez 648 1 fmwafhhgeyawnool 649 1 c 637 1 f 633 1 ywzqaop 631 2复制说明:
由于D:\cfmwafhhgeyawnool 649的文件名长度超过了16个字符,达到了17,所以第一个字符'c'应该被忽略。 记录F:\fop\ywzqaop 631和F:\yay\jc\ywzqaop 631由于文件名和行号相同,因此被视为同一个错误记录,哪怕它们的路径是不同的。 由于循环记录时,只以第一次出现的顺序为准,后面重复的不会更新它的出现时间,仍以第一次为准,所以D:\zwtymj\xccb\ljj\cqzlyaszjvlsjmkwoqijggmybr 645不会被记录。
14.密码验证合格程序(⭐)
密码要求:
1.长度超过8位
2.包括大小写字母.数字.其它符号,以上四种至少三种
3.不能有长度大于2的包含公共元素的子串重复 (注:其他符号不含空格或换行)
满足条件输出:YES,不满足条件输出:NG
本题主要注意条件3的判断
其实就是判断有没有长度为3的子串
C++的内置函数
islower(char c) 是否为小写字母
isuppper(char c) 是否为大写字母
isdigit(char c) 是否为数字
isalpha(char c) 是否为字母
isalnum(char c) 是否为字母或者数字
toupper(char c) 字母小转大
tolower(char c) 字母大转小
#include<bits/stdc++.h>
using namespace std;
bool check1(string str)
{
return str.size()>8;
}
bool check2(string str)
{
int upp=0,lower=0,digit=0,other=0;
for(int i=0;i<str.size();i++)
{
if(isupper(str[i]))upp=1;
else if(islower(str[i]))lower=1;
else if(isdigit(str[i]))digit=1;
else other=1;
}
if(upp+lower+digit+other>=3)return true;//满足符号种类数
else return false;//不满足条件种类数
}
bool check3(string str)
{
set<string>sets;
string tmp;
for(int i=0;i<str.size()-2;i++)
{
tmp=str.substr(i,3); //取出长度为3的字串
if(sets.find(tmp)==sets.end())//找到末尾也没找到说明无该子串
{
sets.insert(tmp);
}
else return false;
}
return true;
}
//主函数
int main()
{
string str;
while (getline(cin,str))
{
if(check1(str)&&check2(str)&&check3(str))cout<<"OK"<<endl;
else cout<<"NG"<<endl;
}
return 0;
}
补充set
set 翻译为集合,是一个内部自动有序且不含重复元素的容器,加入 set 之后可以实现自动排序。
简单来说就是去重+排序(默认从小到大)
find函数
算法中的find是暴力查找,是遍历整个区间,所以时间复杂度是O(N);
而set中的find利用了搜索树的特性,时间复杂度是O(longN);
15.简单密码
现在有一种密码变换算法。
九键手机键盘上的数字与字母的对应: 1--1, abc--2, def--3, ghi--4, jkl--5, mno--6, pqrs--7, tuv--8 wxyz--9, 0--0,把密码中出现的小写字母都变成九键键盘对应的数字,如:a 变成 2,x 变成 9.
而密码中出现的大写字母则变成小写之后往后移一位,如:X ,先变成小写,再往后移一位,变成了 y ,例外:Z 往后移是 a 。
数字和其它的符号都不做变换。
数据范围: 输入的字符串长度满足1≤n≤100
注意:将字母后移动几位
if(a[i]>='A'&&a[i]<='Z')
{
int b=(a[i]-'A'+3)%26;//后移3位
// printf("%d\n",b);
a[i]='A'+b;
}
大小写字母的转换
方法1:大写字母+32=小写字母
方法2:内置函数
char ch=toupper(char c) 字母小转大
char ch=tolower(char c) 字母大转小
#include <iostream>
using namespace std;
void Convert(string str)
{
for(int i=0;i<str.size();i++)
{
if(islower(str[i])){
if(str[i]=='a'||str[i]=='b'||str[i]=='c')str[i]='2';
if(str[i]=='d'||str[i]=='e'||str[i]=='f')str[i]='3';
if(str[i]=='g'||str[i]=='h'||str[i]=='i')str[i]='4';
if(str[i]=='j'||str[i]=='k'||str[i]=='l')str[i]='5';
if(str[i]=='m'||str[i]=='n'||str[i]=='o')str[i]='6';
if(str[i]=='p'||str[i]=='q'||str[i]=='r'||str[i]=='s')str[i]='7';
if(str[i]=='t'||str[i]=='u'||str[i]=='v')str[i]='8';
if(str[i]=='w'||str[i]=='x'||str[i]=='y'||str[i]=='z')str[i]='9';
}
if(isupper(str[i]))
{
str[i]+=32;//大写变小写
//tolower(str[i]);//大写变小写
int tmp=(str[i]-'a'+1)%26;
str[i]=tmp+'a';//往后移一位
}
}
for(int i=0;i<str.size();i++)
cout<<str[i];
}
int main() {
string str;
while(getline(cin,str))
{
Convert(str);
}
return 0;
}