[解题报告]《算法零基础100讲》(第27讲) 字符串算法(七) - 高精度(1)

简介: [解题报告]《算法零基础100讲》(第27讲) 字符串算法(七) - 高精度

零、写在前面


       今天是打卡的第26天,今天稍微调整了点作息好很多了,大家就算要熬夜一定要两点前睡呀,保持六个小时充足睡眠。老规矩,知识点在:


《算法零基础100讲》(第27讲) 字符串算法(七) - 高精度

https://blog.csdn.net/WhereIsHeroFrom/article/details/121347597


一、主要知识点


  1.高精度加法


加数逆序

模拟加法

处理进位

处理前导0

结果逆序

char * addStrings(char * a, char * b){
    char *c;
    int lena = strlen(a);
    int lenb = strlen(b);
    int i, cap, now;
    int av, bv;
    int maxlen = max(lena, lenb);
    inverse(a);                           // 1.
    inverse(b);                           // 1.
    c = (char *)malloc( sizeof(char) * (maxlen + 2) );
    cap = 0;
    for(i = 0; i < maxlen; ++i) {
        av = (i < lena) ? (a[i]-'0') : 0; // 超出范围设置为0
        bv = (i < lenb) ? (b[i]-'0') : 0; // 超出范围设置为0
        now = (av + bv + cap);            // 计算结果
        cap = now / 10;                   // 计算进位
        c[i] = (now % 10) + '0';          // 写入结果
    }
    if(cap) {
        c[i] = '1';                       // 进位 最多是1
        maxlen ++;
    }
    c[maxlen] = '\0';
    inverse(c);                           // 反转
    return c;
}

  2.高精度乘法


乘数逆序

模拟乘法

处理进位

处理前导0

结果逆序

char * multiply(char * a, char * b){
    int i, j, num;
    int lena = strlen(a);
    int lenb = strlen(b);
    int len = lena + lenb;
    int *cnum = (int *)malloc( sizeof(int) * (len+5) );
    char *c = (char *)malloc( sizeof(char) * (len+5) );
    memset( cnum, 0, sizeof(int) * (len+5) );
    inverse(a);                      // 反转
    inverse(b);                      // 反转
    for(i = 0; i < lena; ++i) {
        for(j = 0; j < lenb; ++j) {  // (3)
            cnum[i+j] += (a[i] - '0') * (b[j] - '0');
        }
    }
    for(i = 0; i < len; ++i) {       // 处理进位
        cnum[i+1] += cnum[i] / 10;
        cnum[i] %= 10;
    }
    ++len;
    while(len > 1 && !cnum[len-1]) { // 处理前面的0
        --len;
    }
    for(i = 0; i < len; ++i) {       // 写入字符串
        c[i] = cnum[i] + '0';
    }
    c[len] = '\0';
    inverse(c);                      // 反转
    return c;
}

  3.分治思想


当一个问题过于复杂的时候,先化成多个小问题,然后各个击破。


我就先提出来个概念,等下最后一题的时候我们用用-.-


二、课后习题


1556. 千位分隔数


1556. 千位分隔数

https://leetcode-cn.com/problems/thousand-separator/


题目描述


给你一个整数 n,请你每隔三位添加点(即 "." 符号)作为千位分隔符,并将结果以字符串格式返回。


思路


利用栈的先入后出的特性进行输入数字的反转就好了。加入分隔符。


char * thousandSeparator(int n){
    int zhan[13],zhansize = 0,ansSize = 0;//创建栈 先入后出
    while(n){
        zhan[zhansize++] = n % 10;  //栈赋值
        n /= 10;
    }
    if(!zhansize) zhan[zhansize++] = 0;
    char *ans = malloc(sizeof(char) * (zhansize + zhansize / 3 + 1));//返回字符串空间
    int j = zhansize;
    for(int i = 0;i <zhansize;i++){ //写入字符串信息
        if(i&&!(j%3))   ans[ansSize++] = '.';//够三位就加一个分隔符
        ans[ansSize++] = zhan[--j]+ '0' ;//出栈元素
    }
    ans[ansSize] = 0;
    return ans;
}


1945. 字符串转化后的各位数字之和


1945. 字符串转化后的各位数字之和

https://leetcode-cn.com/problems/sum-of-digits-of-string-after-convert/


题目描述


给你一个由小写字母组成的字符串 s ,以及一个整数 k 。


首先,用字母在字母表中的位置替换该字母,将 s 转化 为一个整数(也就是,'a' 用 1 替换,'b' 用 2 替换,... 'z' 用 26 替换)。接着,将整数 转换 为其 各位数字之和 。共重复 转换 操作 k 次 。


例如,如果 s = "zbax" 且 k = 2 ,那么执行下述步骤后得到的结果是整数 8 :


转化:"zbax" ➝ "(26)(2)(1)(24)" ➝ "262124" ➝ 262124

转换 #1:262124 ➝ 2 + 6 + 2 + 1 + 2 + 4 ➝ 17


思路


由于k>=1,那么至少要做一次加和,那我们第一次读入的时候就把这个做了,也方便我们之后进行运算。之后就是按要求进行位和计算就好了。


int getLucky(char * s, int k){
    int ans = 0,i = 0;
    k--;
    while(s[i]){    //计算位和
        int temp = 0;
        temp = s[i] - 'a' +1;
        if(temp/10) temp = temp /10+temp %10;   //计算位和 最多两位?
        ans += temp;
        i++;
    }
    while(k--){ //迭代计算位和
        int temp = ans;
        ans = 0;
        while(temp){
            ans += temp %10;
            temp /= 10;
        }
    }
    return ans;
}


1796. 字符串中第二大的数字


1796. 字符串中第二大的数字

https://leetcode-cn.com/problems/second-largest-digit-in-a-string/


题目描述


给你一个混合字符串 s ,请你返回 s 中 第二大 的数字,如果不存在第二大的数字,请你返回 -1 。


思路


初始化两个变量,一个是第一大的数字,一个第二大的,初始化为-1.(为啥是-1?题目说的)


根据扫描到的元素进行变量的改变 最后返回就好了。


int secondHighest(char * s){
    int max = -1,max1 = -1;    //两个最大值和次大值
    for(int i = 0;s[i];i++)
        if(s[i]>='0'&&s[i]<='9'){    //扫描到数字
            int temp = s[i] - '0';
            if(temp>max){max1 = max;max = temp;}//比最大值大 更新最大值和次大值
            else if(temp < max && temp > max1)    max1 = temp;//比次大值大但是小于最大值,只更新次大值
        }
    return max1;
}

539. 最小时间差


539. 最小时间差

https://leetcode-cn.com/problems/minimum-time-difference/


题目描述


给定一个 24 小时制(小时:分钟 "HH:MM")的时间列表,找出列表中任意两个时间的最小时间差并以分钟数表示。


思路


先将所有时间转换为分钟的表示,然后做排序,最小值只可能出现在排序后的前后两个元素,或者最前和最后的位置。


int cmp(int *a,int*b){//升序排列
    return *a > *b;
}
int findMinDifference(char ** timePoints, int timePointsSize){
    int hash[timePointsSize],hashSize = 0;
    for(int i = 0;i<timePointsSize;i++)     //转化为分钟
        hash[hashSize++] = (((timePoints[i][0] -'0') * 10) + timePoints[i][1] - '0') * 60 + (timePoints[i][3] - '0')*10 + timePoints[i][4]; 
    qsort(hash,hashSize,sizeof(int),cmp);//排序
    int min = 24*60+hash[0] - hash[hashSize - 1];//最小值赋值为最小和最大值的差 垮了一天
    for(int i = 1;i < hashSize;i++)
        if(min>hash[i]-hash[i-1])   min = hash[i] - hash[i-1];
    return min;
}


3. 罗马数字转整数


3. 罗马数字转整数

https://leetcode-cn.com/problems/roman-to-integer/


题目描述


常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:


I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。

X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。

C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。


给定一个罗马数字,将其转换成整数。


思路


顺序读入,如果读到V、X、L、C、D、M扫描前面的元素是不是对应的可以放置左边的元素,进行统计和就好了。


int romanToInt(char * s){
    int ans = 0;
    for(int i = 0;s[i];i++){
        if(s[i] == 'I') ans += 1;
        else if(s[i] == 'X')
            if(i&&s[i-1]=='I')   ans += 8;//上次统计的时候多加了1 此时就少加
            else ans += 10;
        else if(s[i] == 'V')
            if(i&&s[i - 1] =='I')   ans += 3;
            else ans += 5;
        else if(s[i] == 'L')
            if(i&&s[i - 1] =='X')   ans += 30;
            else ans+= 50;
        else if(s[i] == 'C')
            if(i&&s[i - 1] == 'X') ans += 80;
            else ans += 100;
        else if(s[i] == 'D')
            if(i&&s[i-1] == 'C') ans+=300;
            else ans+= 500;
        else if(s[i] == 'M')
            if(i&&s[i-1] == 'C') ans += 800;
            else ans+= 1000;
    }   
    return ans;
}

12. 整数转罗马数字


12. 整数转罗马数字

https://leetcode-cn.com/problems/integer-to-roman/


题目描述


给你一个整数,将其转为罗马数字。


思路


根据不同元素代表的值进行写入就好了?把左边放元素的看作一个整体就完事了 ,这题不难的。就是情况太多 很烦


char * intToRoman(int num){
    char *ans = malloc(sizeof(char)*1000);
    int anssize = 0;
    while(num/1000){
        num -=1000;
        ans[anssize++]='M';
    }
    while(num/900){
        num-=900;
        ans[anssize++] = 'C';ans[anssize++] = 'M';
    }
    while(num/500){
        num -= 500;
        ans[anssize++] = 'D';
    }
    while(num /400){
        num -= 400;
        ans[anssize++] = 'C';ans[anssize++] = 'D';
    }
    while(num/100){
        num -= 100;
        ans[anssize++] ='C';
    }
    while(num/90){
        num-=90;
        ans[anssize++] = 'X';ans[anssize++] = 'C';
    }
    while(num/50){
        num-=50;
        ans[anssize++] = 'L';
    }
    while(num/40){
        num-=40;
        ans[anssize++] = 'X';ans[anssize++] = 'L';
    }
    while(num/10){
        num -= 10;
        ans[anssize++] = 'X';
    }
    while(num/9){
        num-=9;
        ans[anssize++] = 'I';ans[anssize++] = 'X';
    }
    while(num/5){
        num-=5;
        ans[anssize++] ='V';
    }
    while(num/4){
        num-=4;
        ans[anssize++] = 'I';ans[anssize++] = 'V';
    }
    while(num){
        num --;
        ans[anssize++] = 'I';
    }
    ans[anssize++] = 0;
    return ans;
}


面试题 01.06. 字符串压缩


面试题 01.06. 字符串压缩

https://leetcode-cn.com/problems/compress-string-lcci/


题目描述


字符串压缩。利用字符重复出现的次数,编写一种方法,实现基本的字符串压缩功能。比如,字符串aabcccccaaa会变为a2b1c5a3。若“压缩”后的字符串没有变短,则返回原先的字符串。你可以假设字符串中只包含大小写英文字母(a至z)。


思路


先按照要求进行压缩,然后判断返回值就好了。


char* compressString(char* S){
    int Szie = 0,anssize = 0;//字符串长度和返回长度
    char *ans = malloc(sizeof(char)*60000);    //返回空间
    while(S[Szie]){    //按字符进行判断
        int temp = 0,zhan[5],zhansize = 0;
        while(S[temp+Szie] == S[Szie]) temp++;    //计算元素个数
        ans[anssize++] = S[Szie];
        int temp2 = temp;    //保留元素个数
        while(temp){        //利用栈转化为字符串
            zhan[zhansize++] = temp % 10;
            temp /= 10;
        }
        while(zhansize) ans[anssize++] = zhan[--zhansize]+'0';//转化为字符
        Szie = temp2 + Szie;    //跳过重复元素
    }
    ans[anssize] = 0;
    if(anssize>=Szie)    return S;//判断长度
    return ans;
}
相关文章
|
4天前
|
算法
【优选算法】—— 字符串匹配算法
【优选算法】—— 字符串匹配算法
|
4天前
|
算法 安全
死锁相关知识点以及银行家算法(解题详细步骤)
死锁相关知识点以及银行家算法(解题详细步骤)
8 2
|
4天前
|
算法 搜索推荐 程序员
第六十五练 字符串匹配 - Rabin-Karp算法
第六十五练 字符串匹配 - Rabin-Karp算法
6 1
|
4天前
|
算法 搜索推荐 程序员
第六十四练 字符串匹配 - Boyer-Moore算法
第六十四练 字符串匹配 - Boyer-Moore算法
8 0
|
4天前
|
算法 搜索推荐 程序员
第六十三练 字符串匹配 - KMP算法
第六十三练 字符串匹配 - KMP算法
7 2
|
4天前
|
算法 C语言 人工智能
|
4天前
|
算法
代码随想录算法训练营第五十五天 | LeetCode 583. 两个字符串的删除操作、72. 编辑距离、编辑距离总结
代码随想录算法训练营第五十五天 | LeetCode 583. 两个字符串的删除操作、72. 编辑距离、编辑距离总结
25 1
|
4天前
|
算法
【算法学习--字符串】(不含KMP算法)
【算法学习--字符串】(不含KMP算法)
|
4天前
|
算法 Java
[Java·算法·简单] LeetCode 28. 找出字符串中第一个匹配项的下标 详细解读
[Java·算法·简单] LeetCode 28. 找出字符串中第一个匹配项的下标 详细解读
28 0
|
4天前
|
算法 测试技术 C++
【字符串】【 LCP】【C++算法】2573找出对应 LCP 矩阵的字符串
【字符串】【 LCP】【C++算法】2573找出对应 LCP 矩阵的字符串