積跬步至千里——演算法強化訓練(7)大數問題
阿新 • • 發佈:2019-01-11
大數問題:當感覺用long或int已經不能滿足要求,需要考慮大數問題。大數問題將普通的數學運算,轉移到字串上的操作。大數操作有很多寫法,但是我習慣用以下這個模板,因為對加法 乘法 減法都是一個路子,便於記憶和理解。
大數乘法:
string Multi(string str1, string str2) { int len1 = str1.length(); int len2 = str2.length(); reverse(str1.begin(),str1.end()); reverse(str2.begin(),str2.end()); vector<int> vec(len1+len2,0); int i,j,k,p; //計算每位的乘積 for (i=0;i<len1;++i) for(j=0;j<len2;++j) vec[i+j] += (str1[i]-'0')*(str2[j]-'0'); //處理每一位和進位 for (i=0;i<vec.size()-1;++i) { vec[i+1] +=vec[i]/10; vec[i] = vec[i]%10; } //儲存計算結果 for (p=vec.size()-1;p!=-1;p--)//找到最高位 if(vec[p]!=0) break; if(p==-1) p=0;//只有一位零時候 //構造結果字串 string res(p+1,'0'); for (k = p;k>=0;--k) res[p-k] = char(vec[k]+'0'); return res; }
大數加法:
string AddString(string str1 ,string str2) { if(str1.length()<str2.length()) swap(str1,str2); int len1 = str1.length(); int len2 = str2.length(); reverse(str1.begin(),str1.end()); reverse(str2.begin(),str2.end()); vector<int> vec(len1+1,0); int i,k,p; for (i=0;i<len1;++i) { if(i<len2) vec[i] = (str1[i]-'0')+(str2[i]-'0'); else vec[i] = str1[i]-'0'; } for (i=0;i<len1;++i) { vec[i+1] +=vec[i]/10; vec[i] = vec[i]%10; } for (p=vec.size()-1;p!=-1;p--) if(vec[p]!=0) break; if(p==-1) p=0; string res(p+1,'0'); for (k = p;k>=0;--k) res[p-k] = char(vec[k]+'0'); return res; }
大數減法:
string MinusString(string s1,string s2) { bool minus = false; if(s1.length()<s2.length() || (s1.length()==s2.length() && s1<s2)) { swap(s1,s2); minus = true; } int len1 = s1.length(); int len2 = s2.length(); reverse(s1.begin(),s1.end()); reverse(s2.begin(),s2.end()); vector<int> vec(len1,0); int i,p,k; int borrow=0; for (i=0;i<len1;++i) { if(i<len2) vec[i] = (s1[i]-'0')-(s2[i]-'0'); else vec[i] = s1[i]-'0'; } for (i=0;i<len1;++i) { if(vec[i]<0 || (vec[i]==0&&borrow==1)) { vec[i] += 10-borrow; borrow =1; } else if(vec[i]>0) { vec[i] -= borrow; borrow = 0; } } //儲存計算結果 for (p=vec.size()-1;p!=-1;p--)//找到最高位 if(vec[p]!=0) break; if(p==-1) p=0;//只有一位零時候 //構造結果字串 string res(p+1,'0'); for (k = p;k>=0;--k) res[p-k] = char(vec[k]+'0'); if(minus) res = "-"+res; return res; }
通過以上幾個程式碼,可以看到大數的操作應用了一個類似的模板
判斷基本條件——反轉兩個輸入串——構造vector,並進行運算處理——構造結果串
大數階乘:階乘在n為十幾的時候就會發生溢位,所以要用字串來處理
void Factorial(int n) //n>=1
{
int a[100];
a[0]=1;
int j,p=1,carry;//p代表當前一共有多少位,carry用於儲存進位
for (int i=2;i<=n;++i)
{
for (j=0,carry=0;j<p;++j)
{
a[j] = a[j]*i+carry;
carry = a[j]/10;
a[j] = a[j]%10;
}
while(carry!=0)
{
a[j++] = carry%10;
carry = carry/10;
}
p = j;
}
for (int i = p-1;i>=0;--i)
cout<<a[i];
}
求2的n次方:
string Power(int n) //n<1024
{
string result;
if(n==1) return "2";
if(n & 0x1)//奇數
{
result = Multi(Power((n-1)/2),Power((n-1)/2));
result = Multi(result,"2");
}
else
result = Multi(Power(n/2),Power(n/2));
return result;
}