PTA天梯赛L1刷题总结(三)15分题型(超详细题解)

         多么感人!时隔一年多,我终于来更新15分题型的博文了。突然发现L1的题目量扩充了!一共有哦20道题。哎~都写一遍题解好了。在这里推荐下胡凡的算法笔记!在基础算法和数据结构上给了我很多细致的讲解启发。过去刷题真想有个类型题解便于我总结学习,现在积累了一些可以自己动手写啦!一个学习小建议:刷题不要怕困难,要坚持下去,及时总结!

        首先对20道题进行一个分类吧~

目录

一、哈希映射问题

二、结构体问题

三、简单题(按题意要求写就行,部分题给出代码)

四、字符串处理

五、矩阵处理


一、哈希映射问题

L1-003 个位数统计

此题中N是一个不超过 1000 位的正整数,遇到这样的问题一般采用字符串遍历的方式解决。(超出了整型的范围)。题目要求对 N 中每一种不同的个位数字,以 D:M 的格式在一行中输出该位数字 D 及其在 N 中出现的次数 M。要求按 D 的升序输出。

回顾一下int类型和long long类型有多少位

int类型 -2^31~2^31 -1  【int类型在C语言中占4个字节,即32个二进制位,最高位为符号位】

long long类型  −2^63,2^63−1【long long类型在C语言中占8个字节,即64个二进制位】

int只能表示到10^9,而long long 可以表示到10^18根据不同的情况需定义不同的数据类型。

思路:

根据题目的要求,第一想到的是用哈希表来存储每位数字对应的次数,这个是一一映射的关系。每一位上就是0到9十个数字,用一个长度为10的整型数组就行。对于出现次数为0的,就不用输出了。这里加个判断就可以。

对于字符串问题,首先先读入每一个字符,遇到一个字符,则对应出现次数+1。最后输出时如果映射的值不为0,则按照格式输出即可。

本题有两个注意点

1) memset(s,0,sizeof(s)); 关键,对数组初始化都设置为0,否则会出错。用到这个时需要加上头文件 #include <string.h>

2) 注意遍历时str[i]是一个字符,要str[i]-'0'来转化为int类型

#include <iostream>
#include <string>
#include <string.h>

using namespace std;

int main()
{
    string str;
    int s[10];
    int i;
    cin>>str;
    memset(s,0,sizeof(s)); //关键,对数组初始化都设置为0,否则会出错
    for(i=0;i<str.length();i++)
    {
        s[str[i]-'0']++;    //注意str[i]是一个字符,要str[i]-'0'来转化为int类型
    }
    for(i=0;i<10;i++)
    {
        if(s[i]!=0)
            cout<<i<<":"<<s[i]<<endl;
    }
    return 0;
}

下面给出第二种方法,博主去刷力扣时的常用方法。我们可以利用map来解决这个哈希数组问题。

这种方法有几个学习点

1)定义map的时候记得加上头文件#include <map>

 如map<string,int>就是代表从string类型到int类型的映射,且map默认是按key值从小到大排序。

2)访问map容器内元素方法,一个是通过访问下标,比如下方的mp[c-’0’],还有一种就是通过迭代器(如map<int, int>::iterator it)。通过it->first访问键,it->second访问值。

下边的写法可以这么写

for(map<int,int>::iterator it = mp.begin();it!=mp.end();it++)

{

        cout << it->first << ":" << it->second << endl;

}

3)for(char c:str)这是for循环的一个简便写法,遍历字符串str的每一个字符就是c,也就是方法一中的str[i],比方法一的遍历要方便很多对吧。

#include <iostream>
#include <string>
#include <string.h>
#include <map>

using namespace std;

int main()
{
    string str;
    cin>>str;
    map<int,int> mp;
    for(char c:str)
    {
        mp[c-'0']++;
    }
    map<int, int>::iterator it = mp.begin();
	
	while (it != mp.end()) {
		cout << it->first << ":" << it->second << endl;
		it++;
	}

    return 0;
}

二、结构体问题

L1-005 考试座位号

针对本题,题目的要求是对应每个需要查询的试机座位号码,在一行中输出对应考生的准考证号和考试座位号码,中间用 1 个空格分隔。

思路:

        考虑到每个人是有准考证号、试机座位号、考场座位号的。这时候考虑用结构体代表每个学生。特别是在不同数据类型的变量或数组组合在一起的时候应用结构体能够便于存储。

比如struct studentInfo{int id; char gender; string name;}Bob,stu[10];

其中studentInfo是结构体名,Bob是结构体变量,stu[10]是结构体数组(包含了10个学生的信息)。访问结构体可以通过.或者->

实现:

准考证号是16位数字,可以考虑用string类型来存储。首先遍历给定的N个学生的信息。再依次读入试机号,遍历结构体中是否有相同的试机号,相同则输出其准考证号和考试座位号。

当遍历的次数和循环的内容没有关系时,可以用while(m--)作循环

#include <iostream>
#include <cstdio>
#define N 100000
using namespace std;

struct node
{
    string z;
    int s,k;
}stu[N];
int main()
{
    int i,m,n,l;
    cin>>n;
    for(i=0;i<n;i++)
    {
       cin>>stu[i].z>>stu[i].s>>stu[i].k;
    }
    cin>>m;
    while(m--)
    {
        cin>>l;
        for(i=0;i<n;i++)
        {
            if(stu[i].s==l)
                cout<<stu[i].z<<" "<<stu[i].k<<endl;
        }
    }
    return 0;
}

或者我们可以优化一下,建立试机号到结构体(准考证号,座位号)的映射。下面给出第二种方法

#include <iostream>
#include <cstdio>
#include <map>
#define N 100000
using namespace std;

struct node
{
    string z;//准考证号
    int k; //考场座位号
}stu;

int main()
{
    int i,m,n,l;
    map<int,node> mp;
    cin>>n;
    int s;
    for(i=0;i<n;i++)
    {
       cin>>stu.z>>s>>stu.k;
       mp[s] = stu;
    }
    cin>>m;
    while(m--)
    {
        cin>>l;
        cout<<mp[l].z<<" "<<mp[l].k<<endl;
    }
    return 0;
}

L1-030 一帮一 

        得到全班学生的排名后,在当前尚未分组的学生中,将名次最靠前的学生与名次最靠后的异性学生分为一组。每行输出一组两个学生的姓名小组的输出顺序按照前面学生的名次从高到低排列。

思路:

因为这道题我们不仅要存这个学生排名、姓名、还要存性别。考虑用结构体来代表每一个学生。

输入已经按照名次大小排列了,那遍历的边界在哪里呢?是n/2。要不然再后面差一点的学生就排到前面去了。

因为要和异性组队,那么是不是有可能出现第一名和最后一名同学是同性,于是第一名和倒数第二名同学组队了,那第二名和最后一名是异性,他们组队。那这时候就得考虑有个标志位来记录这个同学是不是组过队了。

实现:

结构体我们上面已经说了,可以定义一个大小为N的结构体数组,在头部宏定义#define N 10000

在输入第i个学生的性别和姓名时,初始化是否组队的标记位为0。

在输出时,按照名词顺序,用两重循环,外层循环先输出名次高的同学名字,再嵌套一个循环,从j=n-1开始,若不满足j>i则跳出。如果这个同学之前未匹配并且和名次高的同学性别不同,则匹配成功,输出这个同学姓名,并置标记位为1。否则break(只会跳出这一层循环!

#include <iostream>
#define N 10000
using namespace std;
struct node
{
    int x,f;
    string m;
}s[N];
int main
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值