第四章
二分法
- 在有序的序列中查找X;
- 求解序列中第一個大於等於x元素的位置
- 查找第一個大於x元素的位置
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
/*查找x*/
int searchX(int data[],int left, int right, int x){
int mid;
while(left<=right){
mid = (left + right)>>1;
if(data[mid] == x) return mid;
else if(data[mid] > x) right = mid + 1;
else left = mid;
}
return -1;
}
/*
求解序列中第一個大於等於x元素的位置
*/
int solve(int data[],int left,int right, int x){
int mid;
while(left < right){ //推出循環的時候left == right
mid = (left + right)>>1;
if(data[mid] >= x){
right = mid;
}else {
left = mid + 1;
}
}
return left;
}
/*查找第一個大於x元素的位置*/
int solve2(int data[],int left, int right, int x){
int mid;
while(left < right){
mid = (left + right)>>1;
if(data[mid] > x) right = mid;
else left = mid + 1;
}
return left;
}
const int n = 10;
int main(){
int A[n] = {1,3,4,6,7,8,10,11,12,15};
int posX = searchX(A,0,n-1,10);
if(posX != -1){
printf("%d-%d\n",posX,A[posX]);
}else{
printf("cannot find x\n");
}
int index = solve(A,0,n-1,9);
printf("%d-%d\n",index,A[index]);
index = solve2(A,0,n-1,6);
printf("%d-%d\n",index,A[index]);
return 0;
}
快速冪
兩種方法,其中迭代方法中採用分解的思路
比如求解2^13= 2^8 * 2^4 * 2^1;
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
/*
求解快速冪 a^b%m;
*/
//迭代方法求解
LL binarypow(LL a,LL b,LL m){
LL ans = 1;
while(b > 0){
if(b & 1){
ans = ans * a % m;
}
a = a*a % m;
b>>=1;
}
return ans;
}
//遞歸方法
LL recursionpow(LL a,LL b, LL m){
if(b == 0) return 1;
if(b & 1) return a*recursionpow(a,b-1,m) % m;
else{
LL mul = recursionpow(a,b>>1,m);//減少計算量
return mul*mul%m;
}
}
int main(){
LL ans = binarypow(2,10,100000);
printf("%lld\n",ans);
ans = recursionpow(2,10,100000);
printf("%lld",ans);
return 0;
}
第五章數學問題(大整數+素數篩+分數問題)
大整數問題
在寫一些編程的題目時候遇到的大整數問題,可以在c++語言做出如下定義並使用。java中有BigDecimal這個類,而在c++只能自己寫一個基本的數據結構數組來保存數據。
代碼如下:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
/*
3 2 1
-1 2 3
-------
*/
struct bign{
int d[1000];
int len;
bign(){
memset(d,0,sizeof(d));//初始化數組
len = 0;
}
};
bign change(string s) {
bign c;
c.len = s.length();
for(int i = 0; i < s.length(); i++){
c.d[i] = s[s.length()-i-1]-'0';
}
return c;
}
void printfArra(int d[],int len){
for(int i = 0; i < len;i++){
printf("%d",d[i]);
}
printf("\n");
}
//高精度加法
bign add(bign a, bign b){
bign c;
int cx = 0;
for(int i = 0; i<a.len || i<b.len;i++){
int temp = a.d[i] + b.d[i] + cx;
c.d[c.len++] = temp % 10;
cx = temp / 10;
}
if(cx != 0){
c.d[c.len++] = cx;
}
return c;
}
//高精度減法
bign devide(bign a, bign b){
bign c;
for(int i = 0; i < a.len || i < b.len;i++){
int temp = a.d[i] - b.d[i];
if(temp < 0){
temp = (a.d[i] + 10) - b.d[i];
a.d[i+1]--;
}
c.d[c.len++] = temp;
}
while(c.len-1>=1 && c.d[c.len-1] == 0) {
c.len--;
}
return c;
}
//大整數的乘法 一個整數*大整數 a*b
bign multiple(bign a, int b){
bign c;
int carry = 0;
for(int i = 0; i < a.len; i++){
int temp = a.d[i] * b + carry;
c.d[c.len++] = temp % 10;
carry = temp / 10;
}
while(carry){
c.d[c.len++] = carry % 10;
carry /= 10;
}
return c;
}
bign divide(bign a, int b, int &r){
//大整數除法 a/b 餘數=r
bign c;
c.len = a.len;
for(int i = c.len-1; i >= 0; i--){
r = r*10 + a.d[i];
if(r < b) c.d[i] = 0;
else {
c.d[i] = r / b;
r = r % b;
}
}
while(c.len - 1>=1 && c.d[c.len-1]==0){ //去除最高位是0的情況
c.len--;
}
return c;
}
void print(bign c){
for(int i = c.len-1; i >= 0;i--){
cout<<c.d[i];
}
}
int main(){
/*
string a,b;
cin>>a>>b; //輸入兩個數
bign n1 = change(a);
bign n2 = change(b);
bign c = add(n1,n2);
print(c);
*/
/*
string a,b;
cin>>a>>b; //輸入兩個數
if(a.compare(b) < 0){
//如果字符串b>a則 做減法的時候要交換a,b,同時輸出符號
swap(a,b);
cout<<"-";
}
bign c = devide(n1,n2);
print(c); //打印相加結果
*/
/*
//大整數的乘法
string a;
int b;
cin>>a>>b;
bign n1 = change(a);
bign c = multiple(n1,b) ;
print(c);
*/
// 大整數除法
string a;
int b;
int r = 0;
cin>>a>>b;
bign n1 = change(a);
bign c = divide(n1,b,r);
print(c);
printf("\nr=%d:",r); //餘數
}
素數問題
經常遇到素數相關問題,有兩種方法。前面的博客我也寫過,今天在重新review一下。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
/*
方法1. 使用常規方法 n%i (i>=2 && i <= sqrt(n) )
方法2.使用素數篩法求解2-n範圍內的素數
*/
bool flag[1000]; //聲明一個標記數組 素數篩法就是以空間換時間的列子
int prime[1000];
int index = 0;
//T1求解n以內的素數
void sovlePrime(int n){
memset(flag,true,sizeof(flag));
for(int i = 2; i <= n; i++) {
if(flag[i]){
prime[index++] = i;
for(int j = i; j <= n; j+=i){
flag[j] = false;
}
}
}
}
//T2求解質因子分解
struct Data{
int a,b; //a是底數 b是指數
};
void devideeNum(int n) {
//將n分解成質數 如180=2^2*3^2*5;
sovlePrime(n); //先求解質數
Data row[10];
int c = 0;
cout<<n<<"=";
for(int i = 0; i < index; i++){
if(n % prime[i] == 0){
//prime[i]是n的一個因子 然後在求解 指數
row[c].a = prime[i];
row[c].b = 0;
while(n % prime[i] == 0){
row[c].b++;
n /= prime[i];
}
c++;
}
}
if(n != 1){ //如果最後n仍然大於1,則說明有一個大於sqrt(n)的質因子
row[c].a = n;
row[c++].b = 1;
}
for(int i = 0; i < c;i++){
if(i > 0){
cout<<"*";
}
cout<<row[i].a<<"^"<<row[i].b;
}
}
int main(){
devideeNum(180) ;
return 0;
}
求最大公約數和最小公倍數
求解最大的公約數和最小公倍數代碼,以及在次基礎之上來求解分數的代碼如下:
#include<cstdio>
#include<string>
#include<algorithm>
using namespace std;
//算法筆記第五章
//求最大公約數 3 6 3
//若a>b gcd(a,b)=gcd(b,a%b); gcd(a,0) = a;
//推理 r=a-b*k; 假設d是a,b的最大公約數。則d也是r的公約數
//r=a%b; 得 d是b和a%b的最大公約數
//這種方法用的是歐幾里得輾轉相除法
int gcd(int a, int b) {
if(b == 0) return a;
else return gcd(b,a%b);
}
//求最小公倍數 ab/d,就是兩個數的乘積/最大公約數
int lcm(int a, int b) {
return a/gcd(a,b)*b;
}
//5.3分數的四則運算
//分數表示 分子和分母
struct Fraction{
int up,down; //up分子 down分母
};
//1.分數的化簡
//down爲非負數,若分數爲負的,則讓分子up 爲負的
//如夠分數恰爲0 ,規定分子爲0 分母爲1
//分子分母沒有除1以外的公約數
Fraction reduction(Fraction res) {
if(res.down < 0){
res.up = -res.up;
res.down = -res.down;
}
if(res.up == 0){
res.down =1;
}else{
int d = gcd(abs(res.up),abs(res.down));
res.up /= d;
res.down /= d;
}
return res;
}
//分數的加法
Fraction addF(Fraction a, Fraction b) {
Fraction c;
c.up = a.up*b.down + b.up*a.down;
c.down = a.down*b.down;
return reduction(c);
}
//分數的減法
Fraction deviceF(Fraction a, Fraction b) {
Fraction c;
c.up = a.up*b.down - b.up*a.down;
c.down = a.down*b.down;
return reduction(c);
}
//分數的乘法
Fraction multiF(Fraction a, Fraction b) {
Fraction c;
c.up = a.up*b.up;
c.down = a.down*b.down;
return reduction(c);
}
//分數的除法
Fraction devideF(Fraction a, Fraction b) {
Fraction c;
c.up = a.up * b.down;
c.down = a.down*b.up;
return reduction(c);
}
int main(){
//求最小公倍數測試
//初始條件a>b
// int ans = lcm(9,3);
// printf("%d",ans);
// 分數的加法測試
/* Fraction a;
a.down = -4;
a.up = 4;
Fraction b = reduction(a);
printf("%d/%d",b.up,b.down);
*/
Fraction a,b;
a.up = 9;
a.down = -4;
b.up = 4;
b.down = 2;
Fraction c = addF(a,b);
printf("%d/%d",c.up,c.down);
return 0;
}
【注】這是我在準備考研複試時候,看《算法筆記》胡凡的書練習的代碼,只想加深一下印象,因此把自己的東西輸出一下。如有錯誤還請指之處,萬分感謝!!!