【Code pratice】—— 成绩统计、星系炸弹、特别数的和、蛇形填数、日志统计

D a t e : 2022 − 10 − 02 \color{FF6699}{Date:2022-10-02} Date20221002

I f \color{FF6699}{If} If I \color{FF6699}{I} I c a n ′ t \color{FF6699}{can't} cant I \color{FF6699}{I} I m u s t ; \color{FF6699}{must;} must; I f \color{FF6699}{If} If I \color{FF6699}{I} I m u s t \color{FF6699}{must} must I \color{FF6699}{I} I c a n ! \color{FF6699}{can!} can!

🍎1. 成绩统计🍎1

🍇题目🍇

编写一个程序,建立了一条单向链表,每个结点包含姓名、学号、英语成绩、数学成绩和C++成绩,并通过链表操作平均最高的学生和平均分最低的学生并且输出。
输入格式
输入n+1行,第一行输入一个正整数n,表示学生数量;接下来的n行每行输入5个数据,分别表示姓名、学号、英语成绩、数学成绩和C++成绩。注意成绩有可能会有小数。

输出格式
输出两行,第一行输出平均成绩最高的学生姓名。第二行输出平均成绩最低的学生姓名。

样例输入

2
yx1 1 45 67 87
yx2 2 88 90 99

🍇思路🍇

科目数量固定,所以求平均成绩最高最低相当于求总分最高最低的即可。

🍇代码🍇

void ScoreCount(int i_StudentNum)
{
    if ((0 > i_StudentNum))
    {
        cout << "Invalid date entered." << endl;
    }

    Student stu[i_StudentNum];
    double scoreSum = 0.0;
    double minSum = 300.0;
    double maxSum = 0.0;
    string minName = "";
    string maxName = "";

    for (int i = 0; i < i_StudentNum; i++)
    {
        cout << "Please input Student [" << i <<"]'s name, id, english score, math score, cplusplus score: " << endl;
        cin >> stu[i].name >> stu[i].id >> stu[i].english >> stu[i].math >> stu[i].cplusplus;
        scoreSum = stu[i].math + stu[i].english + stu[i].cplusplus;

        if (minSum > scoreSum)
        {
            minSum = scoreSum;
            minName = stu[i].name;
        }
        if (maxSum < scoreSum)
        {
            maxSum = scoreSum;
            maxName = stu[i].name;
        }
    }
    cout << "The person with the lowest average score is [" << minName << "]." << endl;
    cout << "The person with the highest average score is [" << maxName << "]." << endl;
}

🍊2. 星系炸弹🍊

🍌题目🍌

在X星系的广袤空间中漂浮着许多X星人造“炸弹”,用来作为宇宙中的路标。
每个炸弹都可以设定多少天之后爆炸。
比如:阿尔法炸弹2015年1月1日放置,定时为15天,则它在2015年1月16日爆炸。
有一个贝塔炸弹,2014年11月9日放置,定时为1000天,请你计算它爆炸的准确日期。

🍌思路🍌

炸弹会在定时达到那天爆炸,也就是当定时时间从N减到0时的那天就是爆炸的准确日期,那么本题只需要通过递减定时时间的同时,计算新的日期即可,要注意的是

  1. 每个月的最后一天时,新增一天,应该将月份增1,日数重置为1
  2. 2月份的准确天数要先判断当前年份是闰年还是平年

🍌代码🍌

int GalaxyBomb(int i_Year, int i_Mon, int i_Day, int i_Timing)
{
    if (!IsValidDate(i_Year, i_Mon, i_Day))
    {
        return -1;
    }

    int curYear = i_Year;
    int curMon = i_Mon;
    int curDay = i_Day;

    while (i_Timing)
    {
        bool IsSpecialDay = false;
        if (2 == curMon)
        {
            if (IsLeapYear(curYear))
            {
                if (29 == curDay)
                {
                    curDay = 1;
                    curMon++;
                    IsSpecialDay = true;
                }
            }
            else
            {
                if (28 == curDay)
                {
                    curDay = 1;
                    curMon++;
                    IsSpecialDay = true;
                }
            }
        }
        else if (sBigMonth(curMon))
        {
            if (12 == curMon)
            {
                if (31 == curDay)
                {
                    curDay = 1;
                    curMon = 1;
                    curYear++;
                    IsSpecialDay = true;
                }
            }
            if (31 == curDay)
            {
                curDay = 1;
                curMon++;
                IsSpecialDay = true;
            }
        }
        else
        {
            if (30 == curDay)
            {
                curDay = 1;
                curMon++;
                IsSpecialDay = true;
            }
        }
        if (!IsSpecialDay)
        {
            curDay++;
        }
        i_Timing--;
    }
    char strDate[100];
    memset(strDate, 0, 100);
    sprintf(strDate, "The bomb will explode on %d-%d-%d", curYear, curMon, curDay);
    cout << strDate << endl;
    return 1;
}

🍍3. 特别数的和🍍

🥭题目🥭

小明对数位中含有 2、0、1、9 的数字很感兴趣(不包括前导 0),在 1 到 40 中这样的数包括 1、2、9、10 至 32、39 和 40,共 28 个,他们的和是 574。
请问,在 1 到 n 中,所有这样的数的和是多少?
输入格式
共一行,包含一个整数 n。

输出格式
共一行,包含一个整数,表示满足条件的数的和。

🥭思路🥭

只需要遍历从1到N的所有数字,如果该数字中包含[2, 0, 1, 9]就进行相加即可

🥭代码🥭

int SumOfSpecialNum(int i_Inter)
{
    if ((0 > i_Inter) || (10000 < i_Inter))
    {
        return -1;
    }

    int o_sum = 0;

    for (int i = 1; i <= i_Inter; i++)
    {
        int j = i;
        while (j)
        {
            int tmp = j % 10;
            if ((2 == tmp) || (0 == tmp) || (1 == tmp) || (9 == tmp))
            {
                cout << i << endl;
                o_sum += i;
                break;
            }
            j /= 10;
        }
    }
    return o_sum;
}

🍒4. 蛇形填数🍒

🍑题目🍑

126715
35814
4913
1012
11
蛇形矩阵如上,容易看出矩阵第二行第二列中的数是5。请你计算矩阵中第20 行第20 列的数是多少?

🍑思路🍑

蛇形矩阵的规律就是碰到边界就往回走,那么本题实际只需要做好边界判定的逻辑即可

  1. 当碰到上边界时,往左下方向走
  2. 当碰到左边界时,往右上方向走
  3. 遍历到要求的位置时停下即可

🍑代码🍑

int SnakeMatrix(int i_X, int i_Y)
{
    if ((0 >= i_X) || (0 >= i_Y))
    {
        return -1;
    }

    int MatrixLen = (i_X > i_Y) ? ((i_X * 2) - 1) : ((i_Y * 2) - 1);
    int MatrixItemStart = 1;
    int i = 0;
    int j = 0;
    bool Process = false;
    vector<vector<int> > Matrix(MatrixLen, vector<int>(MatrixLen, 0)); 

    Matrix[0][0] = MatrixItemStart++;
    while (1)
    {
        if (0 != Matrix[i_X - 1][i_Y - 1])
        {
            break;
        }
        j++;
        while (-1 != j)
        {
            Matrix[i][j] = MatrixItemStart++;
            if (0 == j)
            {
                break;
            }
            i++;
            j--;
        }
        i++;
        while (-1 != i)
        {
            Matrix[i][j] = MatrixItemStart++;
            if (0 == i)
            {
                break;
            }
            i--;
            j++;
        }
    }

    return Matrix[i_X - 1][i_Y - 1];
}

🍋5. 日志统计🍋

🍉题目🍉

小明维护着一个程序员论坛。现在他收集了一份”点赞”日志,日志共有 N 行。
其中每一行的格式是:
ts id
表示在 ts 时刻编号 id 的帖子收到一个”赞”。
现在小明想统计有哪些帖子曾经是”热帖”。
如果一个帖子曾在任意一个长度为 D 的时间段内收到不少于 K 个赞,小明就认为这个帖子曾是”热帖”。
具体来说,如果存在某个时刻 T 满足该帖在 [T,T+D) 这段时间内(注意是左闭右开区间)收到不少于 K 个赞,该帖就曾是”热帖”。
给定日志,请你帮助小明统计出所有曾是”热帖”的帖子编号。
输入格式
第一行包含三个整数 N,D,K。
以下 N 行每行一条日志,包含两个整数 ts 和 id。

输出格式
按从小到大的顺序输出热帖 id。
每个 id 占一行。

输入样例:
7 10 2
0 1
0 10
10 10
10 1
9 1
100 3
100 3

输出样例:
1
3

🍉思路🍉

题目要求:升序输出所有的热帖id

那么关键点就是怎么判断是不是热帖?
存在某个时刻 T 满足该帖在 [T,T+D) 这段时间内(注意是左闭右开区间)收到不少于 K 个赞,该帖就曾是”热帖”。
这里举个例子就比如此时D = 10, K = 2
帖子a和帖子b在1时刻收到一个赞,然后帖子a在10时刻再次收到一个赞,帖子b在11时刻也收到一个赞
对于帖子a来说:在 [1, 11) 这个时间段里收到了两个赞,所以a是热帖
对于帖子b来说:在 [1, 11) 这个时间段里只有一个赞,第二个赞是在11时刻收到的,不在区间内

所以具体思路如下:

  1. 先获取点赞数符合条件的帖子id,同时记录下该id每一个赞对应的时间段
  2. 对第一步获取的热帖id的每一个赞的时刻进行排序,只要其第二个赞的时间减去第一个赞的时间符合热帖条件的id即为热帖id
  3. 最后对热帖id进行排序即可

🍉代码🍉

vector<int> LogStatistics(int i_Nth, int i_Dth, int i_Praisenum)
{
    vector<int> result = {-1};
    if ((1 > i_Nth || 100000 < i_Nth)
     || (1 > i_Dth || 10000 < i_Dth)
     || (1 > i_Praisenum || 100000 < i_Praisenum))
    {
        return result;
    }

    vector<int> IsValidId;                                              // 记录符合条件的ID
    vector<int> IdFrequency(200, 0);                                  // 记录每个ID出现的次数
    vector<vector<int> > IdEveryTime(200, vector<int>(200, 0));     // 记录每个ID每次出现的时间,行为 id, 列为 ts
    for (int i = 0; i < i_Nth; i++)
    {
        int ts = 0;
        int id = 0;
        cout << "Please input [" << i << "]'s ts id: ";
        cin >> ts >> id;
        IdFrequency[id]++;
        if (i_Praisenum == IdFrequency[id])
        {
            IsValidId.push_back(id);
        }
        IdEveryTime[id][IdFrequency[id]] = ts;
    }
    sort(IsValidId.begin() + 1, IsValidId.end());

    for (int i = 0; i < IsValidId.size(); i++)
    {
        vector<int> IdTime;                                     // 记录每个 id 出现的时间
        for (int j = 1; j <= IdFrequency[IsValidId[i]]; j++)
        {
            IdTime.push_back(IdEveryTime[IsValidId[i]][j]);
        }
        sort(IdTime.begin(), IdTime.end());
        if (i_Dth > (IdTime[i_Praisenum - 1] - IdTime[0]))
        {
            result.push_back(IsValidId[i]);
        }
    }
    sort(result.begin(), result.end());
    return result;
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ltd Pikashu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值