算法题-大数相乘问题
2016-03-28 17:49
357 查看
算法题-大数相乘问题
今天在网上看到一个大数相乘的问题,题目是这样的:输入两个整数,要求输出这两个数的乘积。输入的数字可能超过计算机内整形数据的存储范围。
分析:
由于数字无法用一个整形变量存储,很自然的想到用字符串来表示一串数字。然后按照乘法的运算规则,用一个乘数的每一位乘以另一个乘数,然后将所有中间结果按正确位置相加得到最终结果。可以分析得出如果乘数为A和B,A的位数为m,B的位数为n,则乘积结果为m+n-1位(最高位无进位)或m+n位(最高位有进位)。因此可以分配一个m+n的辅存来存储最终结果。为了节约空间,所有的中间结果直接在m+n的辅存上进行累加。最后为了更符合我们的乘法运算逻辑,可以讲数字逆序存储,这样数字的低位就在数组的低下标位置,进行累加时确定下标位置较容易些。
下面是我的解法。
首先是对数组逆序的函数:
按 Ctrl+C 复制代码
void reverseOrder(char* str, int p, int q)
{
char temp;
while(p < q)
{
temp = str[p];
str[p] = str[q];
str[q] = temp;
p ++;
q --;
}
}
然后是完成大数相乘的函数:
按 Ctrl+C 复制代码
char* multiLargeNum(char* A, char* B)
{
int m = strlen(A);
int n = strlen(B);
char* result = new char[m+n+1];
memset(result, '0', m+n);
result[m+n] = '\0';
reverseOrder(A, 0, m-1);
reverseOrder(B, 0, n-1);
int multiFlag; // 乘积进位
int addFlag; // 加法进位
for(int i=0; i <= n-1; i++) // B的每一位
{
multiFlag = 0;
addFlag = 0;
for(int j=0; j <= m-1; j++) // A的每一位
{
// '0' - 48 = 0
int temp1 = (A[j] - 48) * (B[i] - 48) + multiFlag;
multiFlag = temp1 / 10;
temp1 = temp1 % 10;
int temp2 = (result[i+j] - 48) + temp1 + addFlag;
addFlag = temp2 / 10;
result[i+j] = temp2 % 10 + 48;
}
result[i + m] += multiFlag + addFlag;
}
reverseOrder(result, 0, m+n-1); // 逆序回来
return result;
}
按 Ctrl+C 复制代码
最后是测试程序:
按 Ctrl+C 复制代码
int main()
{
char A[] = "962346239843253528686293234124";
char B[] = "93459382645998213649236498";
char *res = multiLargeNum(A, B);
if(res[0] != 48)
printf("%c", res[0]);
printf("%s", res+1);
delete [] res;
return 0;
}
按 Ctrl+C 复制代码
时间复杂度分析:
3个逆序操作的时间分别为O(n)、O(m)、O(m+n),双重循环的时间复杂度为O(mn),则总的时间复杂度为O(mn + (m+n)),通常m+n << mn,因此可近似认为为O(mn)。而且,逆序操作只是为了思考更容易,完全可以去掉。
空间复杂度为O(m+n)
今天在网上看到一个大数相乘的问题,题目是这样的:输入两个整数,要求输出这两个数的乘积。输入的数字可能超过计算机内整形数据的存储范围。
分析:
由于数字无法用一个整形变量存储,很自然的想到用字符串来表示一串数字。然后按照乘法的运算规则,用一个乘数的每一位乘以另一个乘数,然后将所有中间结果按正确位置相加得到最终结果。可以分析得出如果乘数为A和B,A的位数为m,B的位数为n,则乘积结果为m+n-1位(最高位无进位)或m+n位(最高位有进位)。因此可以分配一个m+n的辅存来存储最终结果。为了节约空间,所有的中间结果直接在m+n的辅存上进行累加。最后为了更符合我们的乘法运算逻辑,可以讲数字逆序存储,这样数字的低位就在数组的低下标位置,进行累加时确定下标位置较容易些。
下面是我的解法。
首先是对数组逆序的函数:
按 Ctrl+C 复制代码
void reverseOrder(char* str, int p, int q)
{
char temp;
while(p < q)
{
temp = str[p];
str[p] = str[q];
str[q] = temp;
p ++;
q --;
}
}
然后是完成大数相乘的函数:
按 Ctrl+C 复制代码
char* multiLargeNum(char* A, char* B)
{
int m = strlen(A);
int n = strlen(B);
char* result = new char[m+n+1];
memset(result, '0', m+n);
result[m+n] = '\0';
reverseOrder(A, 0, m-1);
reverseOrder(B, 0, n-1);
int multiFlag; // 乘积进位
int addFlag; // 加法进位
for(int i=0; i <= n-1; i++) // B的每一位
{
multiFlag = 0;
addFlag = 0;
for(int j=0; j <= m-1; j++) // A的每一位
{
// '0' - 48 = 0
int temp1 = (A[j] - 48) * (B[i] - 48) + multiFlag;
multiFlag = temp1 / 10;
temp1 = temp1 % 10;
int temp2 = (result[i+j] - 48) + temp1 + addFlag;
addFlag = temp2 / 10;
result[i+j] = temp2 % 10 + 48;
}
result[i + m] += multiFlag + addFlag;
}
reverseOrder(result, 0, m+n-1); // 逆序回来
return result;
}
按 Ctrl+C 复制代码
最后是测试程序:
按 Ctrl+C 复制代码
int main()
{
char A[] = "962346239843253528686293234124";
char B[] = "93459382645998213649236498";
char *res = multiLargeNum(A, B);
if(res[0] != 48)
printf("%c", res[0]);
printf("%s", res+1);
delete [] res;
return 0;
}
按 Ctrl+C 复制代码
时间复杂度分析:
3个逆序操作的时间分别为O(n)、O(m)、O(m+n),双重循环的时间复杂度为O(mn),则总的时间复杂度为O(mn + (m+n)),通常m+n << mn,因此可近似认为为O(mn)。而且,逆序操作只是为了思考更容易,完全可以去掉。
空间复杂度为O(m+n)
相关文章推荐
- Java 计算两个日期直接相差多少天
- 优步UBER司机全国各地奖励政策汇总 (3月28日-4月3日)
- 每日问题汇总:2016-3-28
- 在O(1)时间删除链表节点
- C#并行编程--命令式数据并行(Parallel.Invoke)---与匿名函数一起理解(转载整理)
- mongodb集群安装,一主二从,replica_set
- 虚幻填坑004:减少starter content占用空间,只保留使用的assets
- 虚幻填坑004:减少starter content占用空间,只保留使用的assets
- Android实践之Drawable的使用
- TCP之再谈解决服务器TIMEWAIT过多的问题
- Java基础------知识点整理(八)-----内部类
- iOS 远程推送的详细配置
- Linux源码包安装过程及注意事项
- 第三次作业:Scanner的学习
- cocos2dx svn上传问题
- 手动创建一个小于10M的类嵌入式linux系统
- 真机调试出现:The identity used to sign the executable is no longer valid
- java 调用webservice的各种方法总结
- Fragment的陷阱
- 双链表相比单链表的优点