【PAT】1100 Mars Numbers (20 分)

46 篇文章 0 订阅
44 篇文章 0 订阅
  • 题目大意:火星数字以13为基数,我需要写一个程序使火星数字和地球数字互相转换。这里只考虑最多两位火星数字。

    • 地球 -> 火星:int(地球 / 13)为火星的十位数,(地球 % 13)为火星的个位数
    • 火星 -> 地球:十位的火星 * 13 + 个位的火星
  • 思路:用2个数组分别表示火星的个位数和火星的十位数

  • 知识点:

    1. string
    2. vector
    3. getline(cin, str):火星数字之间可能有空格,所以用getline(cin, str)接收字符串
    4. isdigit(char)
  • 代码:

    #include <iostream>
    #include <vector>
    #include <string>
    using namespace std;
    
    int main(){
        string one[13] = {"tret", "jan", "feb", "mar", "apr", "may", "jun", "jly", "aug", "sep", "oct", "nov", "dec"};
        string ten[12] = {"tam", "hel", "maa", "huh", "tou", "kes", "hei", "elo", "syy", "lok", "mer", "jou"};
        int n, i, j, k;
        string num;
        cin >> n;
        cin.ignore();   // getline(cin, str)前面有cin,需先ignore一个'\n'
        for(i = 0; i < n; i++){
            getline(cin, num);
            string result;
            if(isdigit(num[0])){    // 地球 -> 火星
                if(int(stoi(num) / 13) != 0)   // 两位数
                    if(stoi(num) % 13 == 0) // 还要13的倍数!!!
                        result = ten[int(stoi(num) / 13) - 1];
                    else
                        result = ten[int(stoi(num) / 13) - 1] + ' ' + one[stoi(num) % 13];
                else    // 一位数
                    result = one[stoi(num) % 13];
            }
            else{   // 火星 -> 地球
                string one_part = "", ten_part = "";
                if(num.size() > 4){
                    ten_part = num.substr(0, 3);
                    one_part = num.substr(4);
                }
                else
                    one_part = num;
    
                if(ten_part == ""){ // 一位数
                    j = 0, k = 0; // 还要考虑13的倍数!!!
                    for(int m = 0; m < 13; m++){
                        if(m < 12 && ten[m] == one_part){   // 从下面复制ten[m] == ten_part忘记改成ten[m] == one_part
                            j = m + 1;  //因为j可能会是0,所以应该+1
                            break;
                        }
                        if(one[m] == one_part){
                            k = m;
                            break;
                        }
                    }
                    if(j != 0)
                        result = to_string(j * 13);
                    else
                        result = to_string(k);
                }
                else{   // 两位数
                    j = 0, k = 0;
                    for(int m = 0; m < 13; m++){
                        if(m < 12 && ten[m] == ten_part)
                            j = m;
                        if(one[m] == one_part)
                            k = m;
                    }
                    result = to_string((j + 1) * 13 + k);
                }
            }
            printf("%s\n", result.c_str());
        }
        return 0;
    }
    

    代码太长了,可以把数字转换过程封装成函数。

  • 改进的代码:

    1. 将转换数字的代码封装成函数,并且用了重载的概念;

    2. while()来找火星数字的下标。

      注意

      1. 若火星数字只有一位时,要判断这个数是不是13的整数
      2. 若火星数字只有一位时,要注意**k==0**的情况。
    #include <iostream>
    #include <vector>
    #include <string>
    using namespace std;
    
    vector<string> one = {"tret", "jan", "feb", "mar", "apr", "may", "jun", "jly", "aug", "sep", "oct", "nov", "dec"};
    vector<string> ten = {"###", "tam", "hel", "maa", "huh", "tou", "kes", "hei", "elo", "syy", "lok", "mer", "jou"};   // 这样更好找
    
    void decode(int num){
        if(int(num / 13) != 0)  // 两位数
            if(num % 13 == 0) // 13的倍数
                printf("%s\n", ten[int(num / 13)].c_str());
            else
                printf("%s\n", (ten[int(num / 13)] + ' ' + one[num % 13]).c_str());
        else
            printf("%s\n", one[num % 13].c_str());
    }
    
    void decode(string num){    // 重载
        int i, j, k;
        string one_part = "", ten_part = "";
        // 获取每部分数字
        if(num.size() > 4){
            ten_part = num.substr(0, 3);
            one_part = num.substr(4);
        }
        else
            one_part = num;
    
        // 转换
        if(ten_part == ""){ // 一位数
            j = 0, k = 0; // 还要考虑13的倍数,所以要设置j来判断是否有该情况;
            while(j < 13 && ten[j] != one_part) j++;
            while(k < 13 && one[k] != one_part) k++;
            if(j > 0 && j < 13) //  13的倍数
                printf("%s\n", to_string(j * 13).c_str());
            else if(k >= 0 && k < 13)   // 还要考虑为tret(0)的情况
                printf("%s\n", to_string(k).c_str());
        }else{   // 两位数
            j = 0, k = 0;
            while(j < 13 && ten[j] != ten_part) j++;
            while(k < 13 && one[k] != one_part) k++;
            printf("%s\n", (to_string(j * 13 + k)).c_str());
        }
    }
    
    int main(){
        int n, i;
        string num;
        cin >> n;
        cin.ignore();   // getline(cin, str)前面有cin,需先ignore一个'\n'
        for(i = 0; i < n; i++){
            getline(cin, num);
            string result;
            if(isdigit(num[0])) // 地球 -> 火星
                decode(stoi(num));
            else   // 火星 -> 地球
                decode(num);
        }
        return 0;
    }
    
  • 总结:

  1. getline(cin, str)前面有cin需先cin.ignore(),再getline(cin, str)

  2. isdigit()不需要调用什么包;

  3. str.substr()分割字符串;

  4. 这里出现段错误的原因: 之前用了while(one[j] != one_part) j++;找火星语对应的数,没考虑到数组越界的问题,改成了用了for去找 ,就能解决段问题;

  5. 可以将完成某项工作的代码封装成函数,如“判断素数”、“数字转换”和“计算和”之类的;

  6. 细节

    1. 有关数字的问题,要注意num == 0的情况

    2. 遇到数字转换的问题,要注意**数值为基数的倍数(num % 基数 == 0 && num / 基数 != 0)**的情况。

      1. 数值为基数的倍数时有单独的表示:在存十位数字的数组里找num / 基数
      2. 数值为基数的倍数时没有单独的表示:直接(num / 基数) * 10
  7. 粗心

    1. 访问数组元素时,经常用错下标,比如:

      for(i = 0; i < 10; i++){
          for(j = 0; j < 5; j++){
              if(s[j] == '0')		// 我经常会粗心写成s[i]
                  printf("%c\n", s[j]);
          }
      }
      
    2. 有时候偷懒,想复制之前写好的部分,会忘记改了,比如:

      if(m < 12 && ten[m] == one_part){   // 从下面复制ten[m] == ten_part忘记改成ten[m] == one_part
      
    3. 有时候会只考虑测试用例给的值,没设置成变量,比如:

      • 测试用例设置有n条,我就直接设置n = 3;
      • 若数为13的整数时,应该都做特殊处理,但我只考虑了测试用例给出的13
    4. 注意while()允许运行的条件是满足条件的时候,还要注意i == 0的情况的!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值