每周算法
一
很高兴每周算法专题终于可以和大家见面,每周算法专题一周更新一次,每次五个算法,算法有难有易,算法均来源于各种经典的算法题以及各大公司招聘时的笔试面试题,我们的目标在于算法的探讨,寻找更好的解决方案,尽量做到每一个算法都给出从易到难的解题过程,从而使自己磨练出一套解决问题的思路,以及遇到新问题时该如何寻找解决方法。
在此给出了本周相应的算法以及源码,视屏教程可以到此观看
http://edu.51cto.com/course/course_id-5071.html
1、 最大公约数
<1> 题目描述:求解两个整数(不能是负数)的最大公约数(要求两数不能同时为0)
<2> 方法一:穷举法
<3> 方法二:相减法
<4> 方法三:欧几里德辗转相除法
<5> 方法四:欧几里德辗转相除法 递归实现
2、 最小公倍数
<1> 题目描述:求解两个整数(不能是负数)的最小公倍数
<2> 方法一:穷举法
<3> 方法二:公式lcm = a * b / gcd(a,b)
3、 二进制中1的个数<本题感谢 编程之美 的提供>
<1> 题目描述:对一个字节的无符号整形变量,求二进制数中1的个数
(要求:执行效率尽可能高)
<2> 方法一:使用模方法
<3> 方法二:使用位操作运算
<4> 方法三:时间复杂度是与1的个数有关的算法
<5> 方法四:分支法
<6> 方法五:查表法
4、 高效进制转换
<1> 题目描述:对一个 unsigned long 的整数,将其转换为对应的16进制数
<2> 方法一:使用数组存储数据
<3> 方法二:使用栈存储数据
<4> 方法三:使用字符串常量高效转换
5、 位设置(bit_set)
<1> 题目描述: 对一个unsigned char 8 bit数据的指定位置0或置1操作,并保持其他位不变。
函数原型:voidbit_set(unsigned char *p_data, unsigned char position, bool flag);
参数说明:p_data 是指定的原数据,position是指定位(取值范围1~8),flag表示是置0还是置1操作
<2> 方法一:分支设置法
<3> 方法二:位操作设置法
源码:
一、最大公约数
1、 穷举法
#include<iostream>
using namespacestd;
unsigned longGCD(unsigned long a, unsigned long b)
{
if(a == 0)
return b;
else if(b == 0)
return a;
else if(a == b)
return a;
unsigned long gcd;
gcd = a>b?b:a;
while(gcd > 1)
{
if((a%gcd==0) &&(b%gcd==0))
return gcd;
gcd--;
}
return gcd;
}
void main()
{
unsigned long a,b;
cout<<"请输入a 和b:>";
cin>>a>>b;
unsigned long gcd = GCD(a,b);
cout<<"gcd ="<<gcd<<endl;
}
2、 相减法
#include<iostream>
using namespacestd;
unsigned longGCD(unsigned long a, unsigned long b)
{
if(a == 0)
return b;
else if(b == 0)
return a;
else if(a == b)
return a;
unsigned long gcd;
while(a != b)
{
gcd = a > b ? (a-=b) : (b-=a);
}
return gcd;
}
void main()
{
unsigned long a,b;
cout<<"请输入a 和b:>";
cin>>a>>b;
unsigned long gcd = GCD(a,b);
cout<<"gcd ="<<gcd<<endl;
}
3、 欧几里德辗转相除法
#include<iostream>
using namespacestd;
unsigned longGCD(unsigned long a, unsigned long b)
{
if(a == 0)
return b;
else if(b == 0)
return a;
else if(a == b)
return a;
unsigned long mod = a % b;
while(mod != 0)
{
a = b;
b = mod;
mod = a % b;
}
return b;
}
void main()
{
unsigned long a,b;
cout<<"请输入a 和b:>";
cin>>a>>b;
unsigned long gcd = GCD(a,b);
cout<<"gcd ="<<gcd<<endl;
}
4、 欧几里德辗转相除法 递归实现
#include<iostream>
using namespacestd;
unsigned longGCD(unsigned long a, unsigned long b)
{
if(b == 0)
return a;
else
return GCD(b, a%b);
}
void main()
{
unsigned long a,b;
cout<<"请输入a 和b:>";
cin>>a>>b;
unsigned long gcd = GCD(a,b);
cout<<"gcd ="<<gcd<<endl;
}
二、最小公倍数
1、 穷举法
#include<iostream>
using namespacestd;
unsigned longLCM(unsigned long a, unsigned long b)
{
if(a * b == 0)
return 0;
unsigned long lcm = a > b ? a : b;
while(1)
{
if((lcm%a==0) &&(lcm%b==0))
break;
lcm++;
}
return lcm;
}
void main()
{
unsigned long a,b;
cout<<"请输入a 和b:>";
cin>>a>>b;
unsigned long lcm = LCM(a,b);
cout<<"lcm ="<<lcm<<endl;
}
2、公式lcm = a * b / gcd(a,b)
#include<iostream>
using namespacestd;
unsigned longGCD(unsigned long a, unsigned long b)
{
if(b == 0)
return a;
else
return GCD(b, a%b);
}
unsigned longLCM(unsigned long a, unsigned long b)
{
if(a * b == 0)
return 0;
return (a*b)/GCD(a,b);
}
void main()
{
unsigned long a,b;
cout<<"请输入a 和b:>";
cin>>a>>b;
unsigned long lcm = LCM(a,b);
cout<<"lcm ="<<lcm<<endl;
}
三、二进制中1的个数
1、使用模方法
#include<iostream>
using namespacestd;
intCount(unsigned char v)
{
int count = 0;
while(v != 0)
{
if(v % 2 == 1)
count++;
v /= 2;
}
return count;
}
void main()
{
unsigned char ch = 255;
int count = Count(ch);
cout<<"count ="<<count<<endl;
}
2、 使用位操作运算
#include<iostream>
using namespacestd;
intCount(unsigned char v)
{
int count = 0;
while(v != 0)
{
count += v & 0x01;
v >>= 1;
}
return count;
}
void main()
{
unsigned char ch = 255;
int count = Count(ch);
cout<<"count ="<<count<<endl;
}
3、 时间复杂度是与1的个数有关的算法
#include<iostream>
using namespacestd;
intCount(unsigned char v)
{
int count = 0;
while(v != 0)
{
v &= (v-1);
count++;
}
return count;
}
void main()
{
unsigned char ch = 255;
int count = Count(ch);
cout<<"count ="<<count<<endl;
}
4、 分支法
#include<iostream>
using namespacestd;
intCount(unsigned char v)
{
int count = 0;
switch (v)
{
case 0x0:
count = 0;
break;
case 0x1:
case 0x2:
case 0x4:
case 0x8:
case 0x10:
case 0x20:
case 0x40:
case 0x80:
count = 1;
break;
case 0x3:
case 0x6:
case 0xc:
case 0x18:
case 0x30:
case 0x60:
case 0xc0:
count = 2;
break;
//...
// [注意] 此处需要把代码补齐
}
return count;
}
void main()
{
unsigned char ch = 255;
int count = Count(ch);
cout<<"count ="<<count<<endl;
}
5、 查表法
#include<iostream>
using namespacestd;
intcountTable[256] =
{
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3,3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3,
3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3,4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3,
4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4,
3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3,4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3,
4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4,4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6,
6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3,4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4,3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5,6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3,
4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5,5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4,
4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6,7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6,
7, 6, 7, 7, 8
};
intCount(unsigned char v)
{
return countTable[v];
}
void main()
{
unsigned char ch = 255;
int count = Count(ch);
cout<<"count ="<<count<<endl;
}
四、进制转换
1、 使用数组存储数据
#include<iostream>
using namespacestd;
char*Convert_16(unsigned long value)
{
static char Buffer[sizeof(unsignedlong)*2+1];
int mod;
for(int i=sizeof(unsigned long)*2-1;i>=0; --i)
{
mod = value % 16;
if(mod < 10)
{
Buffer[i] = mod + '0';
}
else
{
Buffer[i] = (mod-10) + 'A';
}
value /= 16;
}
return Buffer;
}
void main()
{
unsigned long value = 4711;
char *result = Convert_16(value);
cout<<value<<" ="<<"0x"<<result<<endl;
}
2、 使用栈存储数据
#include<iostream>
#include<stack>
using namespacestd;
voidConvert_16(unsigned long value)
{
stack<char> st;
int mod;
while(value != 0)
{
mod = value % 16;
if(mod < 10)
{
st.push(mod+'0');
}
else
{
st.push((mod-10) + 'A');
}
value /= 16;
}
cout<<value<<" ="<<"0x";
while(!st.empty())
{
cout<<st.top();
st.pop();
}
cout<<endl;
}
void main()
{
unsigned long value = 4711;
Convert_16(value);
}
3、使用字符串常量高效转换
#include<iostream>
#include<stack>
using namespacestd;
char*Convert_16(unsigned long value)
{
static char Buffer[sizeof(unsignedlong)*2+1];
for(int i=sizeof(unsigned long)*2-1;i>=0; --i)
{
Buffer[i] ="0123456789ABCDEF"[value%16];
value /= 16;
}
return Buffer;
}
void main()
{
unsigned long value = 4711;
char *result = Convert_16(value);
cout<<value<<" ="<<"0x"<<result<<endl;
}
五、位设置(bit_set)
1、分支设置法
#include<iostream>
using namespacestd;
voidbit_set(unsigned char *p_data, unsigned char position, bool flag)
{
if(flag)//1
{
switch(position)
{
case 1:
*p_data |= 0x01;
break;
case 2:
*p_data |= 0x02;
break;
case 3:
*p_data |= 0x04;
break;
case 4:
*p_data |= 0x04;
break;
case 5:
*p_data |= 0x05;
break;
case 6:
*p_data |= 0x06;
break;
case 7:
*p_data |= 0x07;
break;
case 8:
*p_data |= 0x08;
break;
}
}
else //0
{
switch(position)
{
case 1:
*p_data &= 0x01;
break;
case 2:
*p_data &= 0x02;
break;
case 3:
*p_data &= 0x03;
break;
case 4:
*p_data &= 0x04;
break;
case 5:
*p_data &= 0x05;
break;
case 6:
*p_data &= 0x06;
break;
case 7:
*p_data &= 0x07;
break;
case 8:
*p_data &= 0x08;
break;
}
}
}
void main()
{
bool flag = true;
//bool flag = false;
unsigned char data = 'A';
unsigned char position = 3;
bit_set(&data,position,flag);
cout<<data<<endl;
}
2、 位操作设置法
#include<iostream>
using namespacestd;
voidbit_set(unsigned char *p_data, unsigned char position, bool flag)
{
unsigned char v = 0x01;
if(flag)//1
{
*p_data |= (v<<(position-1));
}
else //0
{
*p_data &= ~(v<<(position-1));
}
}
void main()
{
bool flag = true;
//bool flag = false;
unsigned char data = 'A';
unsigned char position = 3;
bit_set(&data,position,flag);
cout<<data<<endl;
}