每周算法
一
很高兴每周算法专题终于可以和大家见面,每周算法专题一周更新一次,每次五个算法,算法有难有易,算法均来源于各种经典的算法题以及各大公司招聘时的笔试面试题,我们的目标在于算法的探讨,寻找更好的解决方案,尽量做到每一个算法都给出从易到难的解题过程,从而使自己磨练出一套解决问题的思路,以及遇到新问题时该如何寻找解决方法。
在此给出了本周相应的算法以及源码,视屏教程可以到此观看
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
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 ="< } 2、 相减法 #include 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 ="< } 3、 欧几里德辗转相除法 #include 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 ="< } 4、 欧几里德辗转相除法 递归实现 #include 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 ="< } 二、最小公倍数 1、 穷举法 #include 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 ="< } 2、公式lcm = a * b / gcd(a,b) #include 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 ="< } 三、二进制中1的个数 1、使用模方法 #include 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 ="< } 2、 使用位操作运算 #include 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 ="< } 3、 时间复杂度是与1的个数有关的算法 #include 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 ="< } 4、 分支法 #include 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 ="< } 5、 查表法 #include 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 ="< } 四、进制转换 1、 使用数组存储数据 #include 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< } 2、 使用栈存储数据 #include #include using namespacestd; voidConvert_16(unsigned long value) { stack int mod; while(value != 0) { mod = value % 16; if(mod < 10) { st.push(mod+'0'); } else { st.push((mod-10) + 'A'); } value /= 16; } cout< while(!st.empty()) { cout< st.pop(); } cout< } void main() { unsigned long value = 4711; Convert_16(value); } 3、使用字符串常量高效转换 #include #include 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< } 五、位设置(bit_set) 1、分支设置法 #include 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<
} 2、 位操作设置法 #include 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<
}