HW机试1

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的字典序是可以通过<,>重载来实现的,那么我们本质就是利用一种排序算法来实现

  1. 比较相邻元素,前一个比后一个大(或者前一个比后一个小)就交换位置。
  2. 每一对相邻的元素进行重复的工作,从开始对一直到结尾对,这一步完成后,结尾为最大值或者是最小值
  3. 对所以的元素都进行上面的操作 下面是完整代码:
#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. 化繁为简

我们可以这样理解,对于同一个物品,现在它的价格、重要度都是可变的
那么我们只需要对每一个主件尝试如下四种情况:

  1. 仅加入一个主件;
  2. 加入主件和第一个附件;
  3. 加入主件和第二个附件;
  4. 加入主件和两个附件;

在以上四种情况中找到最大值就能回归到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;
}

  • 20
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值