基础算法——高精度

算法复习——高精度

本文主要内容:

  • 高精度加法
  • 高精度减法
  • 高精度乘法(高精度乘低精度、高精度乘高精度)
  • 高精度除法(高精度除以低精度)

主要功能:实现大数的四则运算。
共同思路:将大数存储在字符串中(倒序或者不倒序),然后按位模拟手工计算,将结果填入答案数组中。
注意:这里所讨论的数均为非负整数


1 高精度加法

  • 功能
    1.实现大数相加(废话
  • 时间复杂度:
    o(n)
  • 基本思路:
    1.将两个大数倒序按位存入数组
    2.从大数低位到高位相加,模拟手工计算过程,将每一位的结果存入答案数组
    3.结果数组倒序输出(因为是从低位到高位来存的)
    4.具体实现方式请看代码
  • 注意事项:
    1.注意若用来表进位的变量t在for循环结束后如果大于0,则应把t插入答案数组末尾
  • 经典例题:
    1.模板题:AcWing 791. 高精度加法
//高精度加法函数
//表示传入以字符串形式表示的两个大数a,b
void add(string a, string b)
{
	int A[N], B[N], C[N];
    int lenA = a.size(), lenB = b.size(), lenC = 0;;//C[]为答案数组
    //两个大数倒序存入数组
    for(int i = lenA - 1; i >= 0; i--)A[lenA - 1 - i] = a[i] - '0';
    for(int i = lenB - 1; i >= 0; i--)B[lenB - 1 - i] = b[i] - '0';
    int t = 0;	//用作按位相加的结果及进位
    int len = max(lenA, lenB);
    //模拟手工计算
    for(int i = 0; i < len; i++)
    {
        t += A[i];
        t += B[i];
        C[lenC++] = t % 10;	
        t /= 10;
    }
    if(t)C[lenC++] = t;	//若t大于0,则把t计入答案数组
    //从后往前输出结果
    for(int i = lenC - 1; i >= 0; i--)
        cout << C[i];
}

2 高精度减法

  • 功能:
    1.实现大数相减(废话
  • 时间复杂度:
    o(n)
  • 基本思路:
    1.将两个大数倒序按位存入数组
    2.按照两数大小选择相应的减法函数sub的实参
    3.从大数低位到高位,模拟手工减法计算过程,将每一位的结果存入答案数组
    4.结果数组倒序输出(因为是从低位到高位来存的)
    5.具体实现方式请看代码(把整个程序的代码搬过来了)
  • 注意事项:
    1.只用实现值较大的数减值较小的数的减法函数,小值数减大值数可转化为大值数减小值数,再在结果前添上一个负号即可,这样可以避免分类讨论
    2.注意答案数组要去前缀0
  • 经典例题:
    1.模板题:AcWing 792. 高精度减法
//1<=大数的长度<=100000
#include

using namespace std;

const int N = 1e5 + 5;

int A[N], B[N], C[N];
string a, b;
int lenA, lenB, lenC;
//比较函数:比较两个字符串的大小
bool cmp(string a, string b)
{
    return (a.size() == b.size())? a >= b : a.size() > b.size();
}
//高精度减法函数
void sub(int A[], int B[], int len)	//这里的len是大值数A的长度
{
    int t = 0;
    for(int i = 0; i < len; i++)
    {
        t += A[i];
        t -= B[i];
        C[lenC++] = (t % 10 + 10) % 10;	//t有可能为负数
        if(t < 0)t = -1;//t<0说明补了一位,则相邻更高位数-1
        else t = 0;
    }
    while(C[lenC - 1] == 0 && lenC - 1 > 0)lenC--;	//去前缀0
}

int main()
{
    cin >> a >> b;
    lenA = a.size(), lenB = b.size();
    for(int i = 0; i < lenA; i++)A[lenA - 1 - i] = a[i] - '0';
    for(int i = 0; i < lenB; i++)B[lenB - 1 - i] = b[i] - '0';
    if(cmp(a, b))   //2.注意把len传过去,不同顺序不同len
        sub(A, B, lenA);
    else
    {
        sub(B, A, lenB);
        cout << "-";
    }
    for(int i = lenC - 1; i >= 0; i--)
        cout << C[i];
    return 0;
}

3 高精度乘法

注意: 其实高精度乘高精度算法也可以实现高精度乘低精度,但是时间复杂度要大一些,所以我觉得还是有必要掌握高精度乘低精度的算法。

3.1 高精度乘低精度

  • 功能:
    1.实现大数与小数相乘(废话
  • 时间复杂度:
    o(n)
  • 基本思路:
    1.将大数倒序按位存入数组
    2.将大数从低位到高位与小数相乘,模拟手工乘法计算过程,将每一位的结果存入答案数组
    3.结果数组倒序输出(因为是从低位到高位来存的)
  • 注意事项:
    1.大数所有位都处理完后若t>0,则要用一个循环将t正确放入答案数组中(因为t有可能大于9,所以用循环)
    2.若输入的a或者b有一个为0,则最终求得的答案可能为连续个0,所以在输出答案数组前要加个判断。
  • 经典例题:
    1.模板题:AcWing 793. 高精度乘法
#include

using namespace std;

const int N = 1e5 + 5;

int A[N], C[N], lenA, lenC;
int b;

void mul(string a, int b)
{
    lenA = a.size();
    for(int i = 0; i < lenA; i++)A[i] = a[lenA - 1 - i] - '0';
    int t = 0;
    for(int i = 0; i < lenA; i++)
    {
        t += A[i] * b;
        C[lenC++] = t % 10;
        t /= 10;
    }
    while(t)
    {
        C[lenC++] = t % 10;
        t /= 10;
    }
    //两个数均大于0,则
    if(a != "0" && b)
        for(int i = lenC - 1; i >= 0; i--)
            cout << C[i];
    else cout << 0;
}
int main()
{
    string a;
    cin >> a >> b;
    mul(a, b);
    return 0;
}

3.2 高精度乘高精度

  • 功能:
    1.实现大数与大数相乘(废话
  • 时间复杂度:
    o(n^2)
  • 基本思路:
    1.将两个大数倒序按位存入数组
    2.从低位到高位,模拟手工乘法计算过程,答案数组相应位置加等于两个大数的某两位相乘的结果
    3.从低位到高位处理答案数组,使之变为一个十进制数
    4.从后往前,将答案数组转化为一个用字符串表示的十进制数,返回结果
  • 注意事项:
    1.若输入的num1或者num2有一个为0,则最终求得的答案可能为连续个0,所以在函数开始前判断两个字符串是否有一个为0,若有则直接返回0。
  • 经典例题:
    1.模板题:LeetCode 43. 字符串相乘
  • 拓展练习:
    1.模拟:Acwing1481. 多项式乘积
//字符串num1和num2的长度不大于110
//num1和num2不以0开头
string multiply(string num1, string num2) {
        if(num1 == "0" || num2 == "0")return "0";
        int A[120] = {0}, B[120] = {0}, C[240] = {0};
        int lenA, lenB, lenC;
        lenA = num1.size(), lenB = num2.size();
        //倒序存入数组
        for(int i = lenA - 1; i >= 0; i--)A[lenA - 1 - i] = num1[i] - '0';
        for(int i = lenB - 1; i >= 0; i--)B[lenB - 1 - i] = num2[i] - '0';
        //模拟手工计算乘法过程,直接将结果放入答案数组中,答案数组的每一位都可存一个int数
        for(int i = 0; i < lenA; i++)
            for(int j = 0; j < lenB; j++)
                C[i + j] += A[i] * B[j];
         //按位处理答案数组,使之变为一个十进制数
        int t = 0;
        while((lenC <= lenA + lenB - 2) || t)	//这样写既可以保证t被正确地放入答案数组中
        {
            t += C[lenC];
            C[lenC] = t % 10;
            t /= 10;
            lenC++;
        }
        //将数组中的数转化为字符串输出
        string res;
        for(int i = lenC - 1; i >= 0; i--)
            res += (char)('0' + C[i]);
        return res;
    }

4 高精度除法

  • 功能:
    1.实现大数与小数相除(废话
  • 时间复杂度:
    o(n)
  • 基本思路:
    1.将大数正序按位存入数组
    2.从高位到低位,利用一个变量r,模拟手工除法计算过程
    3.从前往后,输出答案数组,输出余数
  • 注意事项:
    1.正序存大数
    2.答案数组要去前缀0
  • 经典例题:
    1.模板题:AcWing 794. 高精度除法
#include

using namespace std;

const int N = 1e5 + 5;

int A[N], C[N], lenA, lenC;

void div(string a, int b)
{
    
    lenA = a.size();
    for(int i = 0; i < lenA; i++)A[i] = a[i] - '0';
    int r = 0;	//r保存余数
    for(int i = 0; i < lenA; i++)
    {
        r = r * 10 + A[i];
        C[lenC++] = r / b;
        r %= b;
    }
    int start = 0;
    while(C[start] == 0 && start + 1 < lenC)start++;
    for(int i = start; i < lenC; i++)
        cout << C[i];
    cout << endl << r;
}
int main()
{
    int b;
    string a;
    cin >> a >> b;
    div(a, b);
    return 0;
}

关于高精度数除以高精度数的算法目前我还不会,后续可能会更新~

你可能感兴趣的:(算法小结,算法)