【PAT】01 字符串处理

01 字符串处理

AcWing 1473. A + B 格式

问题描述

分析

  • 相加得到结果后,转为指定形式的字符串输出即可。

代码

  • C++
#include <iostream>

using namespace std;

int main() {

    int a, b;
    cin >> a >> b;
    int c = a + b;
    string num = to_string(c);
    string res;

    for (int i = num.size() - 1, j = 0; i >= 0; i--) {
        res = num[i] + res;
        j++;
        if (j % 3 == 0 && i && num[i - 1] != '-') res = ',' + res;
    }

    cout << res << endl;

    return 0;
}

AcWing 1477. 拼写正确

问题描述

分析

  • 以字符串的形式读入数据,然后将每位相加,最后打表输出即可。

代码

  • C++
#include <iostream>

using namespace std;

int main() {
    
    string num;
    cin >> num;
    int sum = 0;
    for (auto c : num) sum += c - '0';
    
    string str = to_string(sum);
    string name[] = {
        "zero", "one", "two", "three", "four",
        "five", "six", "seven", "eight", "nine"
    };
    for (auto c : str) cout << name[c - '0'] << ' ';
    
    return 0;
}

AcWing 1478. 签到与签出

问题描述

分析

  • 本题相当于求解一个最小值和一个最大值,每次读取一条记录更新答案即可。

代码

  • C++
#include <iostream>

using namespace std;

int n;

int main() {
    
    string open_id, open_time;
    string close_id, close_time;
    
    cin >> n;
    for (int i = 0; i < n; i++) {
        string id, in_time, out_time;
        cin >> id >> in_time >> out_time;
        
        // 更新开门的人
        if (!i || in_time < open_time) {
            open_id = id;
            open_time = in_time;
        }
        
        // 更新关门的人
        if (!i || out_time > close_time) {
            close_id = id;
            close_time = out_time;
        }
    }
    
    cout << open_id << ' ' << close_id << endl;
    
    return 0;
}

AcWing 1519. 密码

问题描述

分析

  • 按照题目要求模拟一遍即可。

代码

  • C++
#include <iostream>

using namespace std;

const int N = 1010;

int n;
string name[N], pwd[N];  // 记录被修改的记录的用户名和密码

string change(string str) {
    string res;
    for (auto c : str) {
        if (c == '1') res += '@';
        else if (c == '0') res += '%';
        else if (c == 'l') res += 'L';
        else if (c == 'O') res += 'o';
        else res += c;
    }
    return res;
}

int main() {
    
    cin >> n;
    int m = 0;  // 需要修改的用户的数量
    for (int i = 0; i < n; i++) {
        string cur_name, cur_pwd;
        cin >> cur_name >> cur_pwd;
        string changed_pwd = change(cur_pwd);
        
        if (cur_pwd != changed_pwd) {
            name[m] = cur_name;
            pwd[m] = changed_pwd;
            m++;
        }
    }
    
    if (!m) {
        if (n == 1) puts("There is 1 account and no account is modified");
        else printf("There are %d accounts and no account is modified\n", n);
    } else {
        cout << m << endl;
        for (int i = 0; i < m; i++) cout << name[i] << ' ' << pwd[i] << endl;        
    }

    return 0;
}

AcWing 1520. 男孩 vs 女孩

问题描述

分析

  • 按照题目要求模拟一遍即可。

代码

  • C++
#include <iostream>

using namespace std;

int main() {
    
    int n;
    cin >> n;
    
    string girl_name, girl_id;  // 女生第一名的信息
    int girl_score;
    string boy_name, boy_id;  // 男生倒数第一名的信息
    int boy_score;
    
    for (int i = 0; i < n; i++) {
        string name, sex, id;
        int score;
        cin >> name >> sex >> id >> score;
        
        if (sex == "F") {
            if (girl_name.empty() || girl_score < score) {
                girl_name = name;
                girl_id = id;
                girl_score = score;
            }
        } else {
            if (boy_name.empty() || boy_score > score) {
                boy_name = name;
                boy_id = id;
                boy_score = score;
            }
        }
    }
    
    if (girl_name.empty()) puts("Absent");
    else cout << girl_name << ' ' << girl_id << endl;
    
    if (boy_name.empty()) puts("Absent");
    else cout << boy_name << ' ' << boy_id << endl;
    
    if (girl_name.size() && boy_name.size()) cout << girl_score - boy_score << endl;
    else cout << "NA" << endl;
    
    return 0;
}

AcWing 1534. 字符串减法

问题描述

分析

  • 使用哈希表统计出字符串b中存在的字符,然后遍历字符串a中的所有字符c,如果c在哈希表中没有出现,则将c加到结果中即可。

代码

  • C++
#include <iostream>
#include <unordered_set>

using namespace std;

int main() {
    
    string a, b;
    getline(cin, a);
    getline(cin, b);
    
    unordered_set<char> S;
    for (auto c : b) S.insert(c);
    
    string res;
    for (auto c : a)
        if (!S.count(c))
            res += c;
    
    cout << res << endl;
    
    return 0;
}

AcWing 1557. 说话方式

问题描述

分析

  • 将每个单词切分出来,然后全部转化为小写,与此同时使用哈希表统计每个单词出现的次数。

  • 之后遍历哈希表,找到出现次数最多且字典序最小的单词输出即可。

代码

  • C++
#include <iostream>
#include <unordered_map>

using namespace std;

bool check(char c) {
    if (c >= '0' && c <= '9') return true;
    if (c >= 'a' && c <= 'z') return true;
    if (c >= 'A' && c <= 'Z') return true;
    return false;
}

char to_lower(char c) {
    if (c >= 'A' && c <= 'Z') return c + 'a' - 'A';
    return c;
}

int main() {
    
    string str;
    getline(cin, str);
    
    unordered_map<string, int> hash;  // (单词, 出现次数)
    
    for (int i = 0; i < str.size(); i++)
        if (check(str[i])) {
            string word;
            int j = i;
            while (j < str.size() && check(str[j])) word += to_lower(str[j++]);
            
            hash[word]++;
            i = j;
        }
    
    string word;
    int cnt = -1;
    for (auto item : hash) 
        if (item.second > cnt || item.second == cnt && item.first < word) {
            word = item.first;
            cnt = item.second;
        }
    
    cout << word << ' ' << cnt << endl;
    
    return 0;
}

AcWing 1547. 约会

问题描述

分析

  • 按照题目要求模拟一遍即可。

代码

  • C++
#include <iostream>

using namespace std;

int main() {
    
    string a, b, c, d;
    cin >> a >> b >> c >> d;
    
    int k = 0;
    while (true) {
        if (a[k] == b[k] && a[k] >= 'A' && a[k] <= 'G') break;
        k++;
    }
    char weekdays[7][4] = {"MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};
    printf("%s ", weekdays[a[k] - 'A']);
    
    k++;
    while (true) {
        if (a[k] == b[k] && (a[k] >= '0' && a[k] <= '9' || a[k] >= 'A' && a[k] <= 'N')) break;
        k++;
    }
    printf("%02d:", a[k] <= '9' ? a[k] - '0' : a[k] - 'A' + 10);
    
    for (int i = 0; ; i++)
        if (c[i] == d[i] && (c[i] >= 'a' && c[i] <= 'z' || c[i] >= 'A' && c[i] <= 'Z')) {
            printf("%02d", i);
            break;
        }
    
    return 0;
}

AcWing 1493. 电话账单

问题描述

分析

  • 因为需要按照人名的字典序输出每个人的信息,因此可以使用map记录每个人的信息,每个人可能有多条通话记录,使用vector记录这些信息,每条信息用一个结构体存储。

  • 为了方便计算时间之差,这里将所有时间转化为相对于当月零时零分过去的时间。这样也方便排序。

  • 为了方便计算任意两个时刻的花费,可以使用前缀和数组的技巧。

  • 另外还需要将美分转化为美元。

代码

  • C++
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <map>
#include <cmath>
#include <algorithm>

using namespace std;

const int N = 1010, M = 31 * 1440 + 10;

int n;
int cost[24];  // 每个时间段的花费
double sum[M];  // 从当月1号00:00开始到每个时刻所花费的钱数, 例如sum[1]表示00:00~00:01的花费

struct Record {
    int minutes;  // 从当月1号00:00经过的时间
    string state;
    string format_time;
    
    bool operator< (const Record& w) const {
        return minutes < w.minutes;
    }
};

map<string, vector<Record>> persons;

int main() {
    
    for (int i = 0; i < 24; i++) scanf("%d", &cost[i]);
    // 例如i = 60, 表示sum[60] = sum[59] + cost[59 / 60] / 100.0;
    for (int i = 1; i < M; i++) sum[i] = sum[i - 1] + cost[(i - 1) % 1440 / 60] / 100.0;  // 美分转化为美元
    
    // 处理输入
    cin >> n;
    char name[25], state[10], format_time[20];
    int month, day, hour, minute;
    for (int i = 0; i < n; i++) {
        scanf("%s %d:%d:%d:%d %s", name, &month, &day, &hour, &minute, state);
        sprintf(format_time, "%02d:%02d:%02d", day, hour, minute);
        
        int minutes = (day - 1) * 1440 + hour * 60 + minute;
        persons[name].push_back({minutes, state, format_time});
    }
    
    // 依次处理每个人
    for (auto &person : persons) {
        auto name = person.first;
        auto records = person.second;
        sort(records.begin(), records.end());
        
        double total = 0;  // 总花费
        for (int i = 0; i + 1 < records.size(); i++) {
            auto a = records[i], b = records[i + 1];
            if (a.state == "on-line" && b.state == "off-line") {
                if (!total) printf("%s %02d\n", name.c_str(), month);
                cout << a.format_time << ' ' << b.format_time;
                
                double c = sum[b.minutes] - sum[a.minutes];
                printf(" %d $%.2lf\n", b.minutes - a.minutes, c);
                total += c;
            }
        }
        
        if (total) printf("Total amount: $%.2lf\n", total);
    }
    
    return 0;
}

AcWing 1494. 银行排队

问题描述

分析

  • 使用一个优先队列存储m个窗口的空闲时间点 。

  • 读入所有的人,按照到达时间进行排序,然后依次处理每个人,每次 从优先队列中弹出一个时间w,这代表在w时刻有一个窗口空闲,此时可以有一个人到这个窗口,计算该人的等待时间,加到答案中。

  • 如果当前考虑的人达到的时间超过了下午五点,后面的人就不需要考察了。

  • 另外需要注意即使有窗口空闲,但可能人还没来,因此窗口此时需要等待顾客。

代码

  • C++
#include <iostream>
#include <queue>
#include <algorithm>

using namespace std;

const int N = 10010;

int n, m;

struct Person {
    int arrive_time;
    int service_time;
    
    bool operator< (const Person& t) const {
        return arrive_time < t.arrive_time;
    }
} persons[N];

int main() {
    
    cin >> n >> m;
    for (int i = 0; i < n; i++) {
        int hour, minute, second, service_time;
        scanf("%d:%d:%d %d", &hour, &minute, &second, &service_time);
        service_time = min(service_time, 60);
        persons[i] = {hour * 3600 + minute * 60 + second, service_time * 60};
    }
    
    priority_queue<int, vector<int>, greater<int>> windows;  // 优先队列存储窗口
    for (int i = 0; i < m; i++) windows.push(8 * 3600);
    
    sort(persons, persons + n);
    
    int sum = 0, cnt = 0;  // sum: 等待时间; cnt: 服务的人数
    for (int i = 0; i < n; i++) {
        auto person = persons[i];
        int w = windows.top();
        windows.pop();
        if (person.arrive_time > 17 * 3600) break;
        
        int start_time = max(person.arrive_time, w);  // 开始服务该人的时间
        sum += start_time - person.arrive_time;
        cnt++;
        
        windows.push(start_time + person.service_time);  // 下次窗口空闲的时间
    }
    
    printf("%.1lf\n", (double)sum / cnt / 60);
    
    return 0;
}

AcWing 1503. 乒乓球

问题描述

分析

代码

  • C++

AcWing 1546. 它们是否相等

问题描述

分析

  • 总体思路是首先将两个字符串转为题目对应形式,然后对比是否相同后输出。具体转化步骤如下:

    (1)找到小数点的位置,并将小数点去掉;

    (2)去掉前导0;

    (3)对齐到n位;

    (4)拼接成题目要求字符串返回

代码

  • C++
#include <iostream>

using namespace std;

string change(string a, int n) {
    
    // 第一步:找到小数点的位置,并将小数点去掉
    int k = a.find('.');
    if (k == -1) a += '.', k = a.find('.');
    a = a.substr(0, k) + a.substr(k + 1);
    // 第二步:去掉前导0
    while (a.size() && a[0] == '0') a = a.substr(1), k--;
    if (a.empty()) k = 0;  // 说明a是0
    // 第三步:对齐到n位
    if (a.size() >= n) a = a.substr(0, n);
    else a += string(n - a.size(), '0');
    // 第四步:拼接成题目要求字符串返回
    return "0." + a + "*10^" + to_string(k);
}

int main() {
    
    int n;
    string a, b;
    cin >> n >> a >> b;
    
    string A = change(a, n);
    string B = change(b, n);
    
    if (A == B) cout << "YES " << A << endl;
    else cout << "NO " << A << ' ' << B << endl;
    
    return 0;
}

AcWing 1559. 科学计数法

问题描述

分析

  • 分为如下步骤:

    (1)如果是负数,先输出一个负号;

    (2)得到底数和指数部分,并让小数点向前移动一位,指数加一;

    (3)根据指数的整数得到结果。

代码

  • C++
#include <iostream>

using namespace std;

int main() {
    
    string s;
    cin >> s;
    
    if (s[0] == '-') cout << '-';
    
    // 例如: +1.23400E-03, 则会得到 a=123400, p=-2
    int k = s.find('E');
    string a = s[1] + s.substr(3, k - 3);
    int p = stoi(s.substr(k + 1));
    p++;
    
    if (p <= 0) a = "0." + string(-p, '0') + a;
    else if (p >= a.size()) a += string(p - a.size(), '0');
    else a = a.substr(0, p) + '.' + a.substr(p);
    
    cout << a << endl;
    
    return 0;
}

AcWing 1563. Kuchiguse

问题描述

分析

  • 我们需要求出给定多个字符串的最长公共后缀。

  • 可以从后向前遍历第一个字符串,然后考察其他字符串对应位置是否和第一个字符串对应位置相同。

代码

  • C++
#include <iostream>

using namespace std;

const int N = 110;

int n;
string s[N];

int main() {
    
    cin >> n;
    getchar();
    for (int i = 0; i < n; i++) getline(cin, s[i]);
    
    string res;
    for (int i = s[0].size() - 1, j = 1; i >= 0; i--, j++) {  // j代表考察的是倒数第j个字母
        bool flag = false;
        char c = s[0][i];
        for (int i = 1; i < n; i++) {
            string str = s[i];
            if (j > str.size() || str[str.size() - j] != c) {
                flag = true;
                break;
            }
        }
        if (flag) break;
        res = c + res;
    }
    
    if (res.empty()) cout << "nai" << endl;
    else cout << res << endl;
    
    return 0;
}

AcWing 1568. 中文读数字

问题描述

分析

  • 因为最多九位,我们将其拆为三个数字进行读,使用work函数返回一个四位数的读法。

  • 两个四位数之间,如果后面一个四位数小于1000,说明该四位数千位是0,如果此时答案的结尾不是0,这加上0

代码

  • C++
#include <iostream>
#include <vector>

using namespace std;

string num1[] = {
    "ling", "yi", "er", "san", "si",
    "wu", "liu", "qi", "ba", "jiu"
};

bool check(string s) {
    return s.size() >= 5 && s.substr(s.size() - 5) == "ling ";
}

// 给定一个非零的四位数,返回其读法
// 1030: yi Qian ling san Shi
// 521: wu Bai er Shi yi
// 2008: er Qain ling ba
// 900: jiu Bai
string work(int n) {
    
    vector<int> num;
    while (n) num.push_back(n % 10), n /= 10;
    
    string num2[] = {"", "Shi", "Bai", "Qian"};
    
    string res;
    for (int i = num.size() - 1; i >= 0; i--) {
        int t = num[i];
        
        if (t) res += num1[t] + " ";  // t不是0
        else if (!check(res)) res += "ling ";  // t是0,当前res最后不是0,则增加一个0
        
        if (t && i) res += num2[i] + " ";  // t不是0, 并且不是最低位
    }
    if (check(res)) res = res.substr(0, res.size() - 5);  // 最后的0需要删除
    
    return res;
}

int main() {
    
    int n;
    cin >> n;
    
    if (!n) puts("ling");
    else {
        if (n < 0) cout << "Fu ", n = -n;
        
        vector<int> num;
        while (n) num.push_back(n % 10000), n /= 10000;
        
        string num3[] = {"", "Wan", "Yi"};
        
        string res;
        for (int i = num.size() - 1; i >= 0; i--) {
            int t = num[i];
            
            if (t < 1000) {  // 此时千位为0
                if (res.size() && !check(res)) res += "ling ";
            }
            if (t) res += work(t);  // 如果t不是0,则加上这四位的读法
            if (t && i) res += num3[i] + " ";  // 如果t不是0, 并且不是最低位
        }
        
        if (check(res)) res = res.substr(0, res.size() - 5);
        
        res.pop_back();
        cout << res << endl;
    }
    
    return 0;
}

AcWing 1570. 坏掉的键盘

问题描述

分析

  • 同时遍历两个字符串a、b,当a中存在某个字符,但b中不存在时,说明该字符对应的键损坏,输出即可,并标记为已经输出,防止多次输出。

代码

  • C++
#include <iostream>

using namespace std;

int main() {
    
    string a, b;
    cin >> a >> b;
    
    bool st[256] = {0};
    b += '#';  // 这样就不用特判b的结束位置了
    for (int i = 0, j = 0; i < a.size(); i++) {
        char x = toupper(a[i]), y = toupper(b[j]);
        if (x == y) j++;
        else {
            if (!st[x]) cout << x, st[x] = true;
        }
    }
    
    return 0;
}

AcWing 1598. 求平均值

问题描述

分析

  • 本题实质上是一个语法题。使用try catch解决。

代码

  • C++
#include <iostream>

using namespace std;

int main() {
    
    int n;
    cin >> n;
    
    int cnt = 0;  // 合法数据个数
    double sum = 0;  // 合法数据之和
    
    while (n--) {
        string num;
        cin >> num;
        
        double x;
        bool success = true;
        try {
            size_t idx;  // 记录num转化为浮点数使用到了多少位
            x = stof(num, &idx);

            if (idx < num.size())  // 说明可能是"123ab"的形式
                success = false;
        } catch (...) {
            success = false;
        }
        
        if (x < -1000 || x > 1000) success = false;
        
        int k = num.find('.');
        if (k != -1 && num.size() - k > 3) success = false;
        
        if (success) cnt++, sum += x;
        else printf("ERROR: %s is not a legal number\n", num.c_str());
    }
    
    if (cnt > 1) printf("The average of %d numbers is %.2lf\n", cnt, sum / cnt);
    else if (cnt == 1) printf("The average of 1 number is %.2lf\n", sum);
    else printf("The average of 0 numbers is Undefined\n");
    
    return 0;
}

AcWing 1617. 微博转发抽奖

问题描述

分析

  • 按照题目要求模拟一遍即可。可以使用哈希表存储已经中奖的同学,防止重复输出。

代码

  • C++
#include <iostream>
#include <unordered_set>

using namespace std;

const int N = 1010;

int m, n, s;
string name[N];

int main() {
    
    cin >> m >> n >> s;
    for (int i = 1; i <= m; i++) cin >> name[i];
    
    unordered_set<string> hash;
    int k = s;
    while (k <= m) {
        if (hash.count(name[k])) k++;
        else {
            hash.insert(name[k]);
            cout << name[k] << endl;
            k += n;
        }
    }
    
    if (hash.empty()) puts("Keep going...");
    
    return 0;
}

AcWing 1634. PAT单位排行

问题描述

分析

  • 首先使用哈希表统计出每个学校的记录。然后将这些记录存放到vector中,排序后输出即可。

代码

  • C++
#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>

using namespace std;

struct School {
    string name;
    int cnt;
    double sum;
    
    School() : cnt(0), sum(0) {}
    
    bool operator< (const School &t) const {
        if (sum != t.sum) return sum > t.sum;
        if (cnt != t.cnt) return cnt < t.cnt;
        return name < t.name;
    }
};

int main() {
    
    int n;
    cin >> n;
    
    unordered_map<string, School> schools;
    for (int i = 0; i < n; i++) {
        string id, sch;
        double grade;
        cin >> id >> grade >> sch;
        
        for (auto &c : sch) c = tolower(c);
        
        if (id[0] == 'B') grade /= 1.5;
        else if (id[0] == 'T') grade *= 1.5;
        
        schools[sch].name = sch;
        schools[sch].cnt++;
        schools[sch].sum += grade;
    }
    
    vector<School> res;
    for (auto item : schools) {
        item.second.sum = (int) (item.second.sum + 1e-8);  // 浮点精度问题
        res.push_back(item.second);
    }
    
    sort(res.begin(), res.end());
    
    cout << res.size() << endl;
    int rank = 1;
    for (int i = 0; i < res.size(); i++) {
        auto s = res[i];
        if (i && s.sum != res[i - 1].sum) rank = i + 1;
        printf("%d %s %d %d\n", rank, s.name.c_str(), (int)s.sum, s.cnt);
    }
    
    return 0;
}

AcWing 1647. 解码PAT准考证

问题描述

分析

  • 使用结构体存储每一条记录,使用vector存储所有记录。

  • 对于不同类型的查询,直接遍历一遍所有记录,将符合条件的记录存储下来,最后得到统计结果输出即可。

代码

  • C++
#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_map>

using namespace std;

const int N = 10010;

int n, m;

struct Student {
    string info;
    string level;  // 级别
    string room;  // 考场
    string date;  // 考试时间
    string id;  // 考号
    int grade;
    
    bool operator< (const Student &t) const {
        if (grade != t.grade) return grade > t.grade;
        return info < t.info;
    }
} p[N];

int main() {
    
    cin >> n >> m;
    for (int i = 0; i < n; i++) {
        string info;
        int grade;
        cin >> info >> grade;
        p[i].info = info;
        p[i].level = info.substr(0, 1);
        p[i].room = info.substr(1, 3);
        p[i].date = info.substr(4, 6);
        p[i].id = info.substr(10);
        p[i].grade = grade;
    }
    
    for (int i = 1; i <= m; i++) {
        string t, c;
        cin >> t >> c;
        
        printf("Case %d: %s %s\n", i, t.c_str(), c.c_str());
        if (t == "1") {
            
            vector<Student> students;
            for (int i = 0; i < n; i++)
                if (p[i].level == c)
                    students.push_back(p[i]);
            
            sort(students.begin(), students.end());
            
            if (students.empty()) puts("NA");
            else {
                for (auto &s : students)
                    printf("%s %d\n", s.info.c_str(), s.grade);
            }
            
        } else if (t == "2") {
            int cnt = 0, sum = 0;
            for (int i = 0; i < n; i++)
                if (p[i].room == c) {
                    cnt++;
                    sum += p[i].grade;
                }
            if (!cnt) puts("NA");
            else printf("%d %d\n", cnt, sum);
        } else {
            unordered_map<string, int> hash;
            for (int i = 0; i < n; i ++ )
                if (p[i].date == c)
                    hash[p[i].room] ++ ;

            vector<pair<int, string>> rooms;
            for (auto item : hash) rooms.push_back({-item.second, item.first});

            sort(rooms.begin(), rooms.end());
            if (rooms.empty()) puts("NA");
            else
                for (auto room : rooms)
                    printf("%s %d\n", room.second.c_str(), -room.first);
        }
    }
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值