7.8 KiB
数值问题
这部分都是一些数学几何计算方面的问题。主要由:
- 位运算
- 随机数
- 大数问题
求1+2+…+n
要求不能使用乘除法、for、while、if、else、switch、case等关键字以及条件判断语句(A?B:C)。
思路:这是等差数列求和公式, 1+2+3.......+N =(n+1)n/2
分析:
- 不能使用循环,那就用递归
- 递归需要终止递归的条件判断语句,这里也不能用if,想其他办法,可以使用 &&逻辑与 运算符(在n>0条件满足是,才会指向后面的递归语句
int (n){
int sum=0;
(n>0) && sum=n+factorial(n-1)
return sum;
}
大数阶乘(factorial)
int factorial(n){
int sum=0;
(n>0) && sum=n+factorial(n-1)
return sum;
}
整数的二进制表示中1的个数
题目:输入一个整数,求该整数的二进制表达中有多少个1。例如输入10,由于其二进制表示为1010,有两个1,因此输出2。
分析:
这是一道很基本的考查位运算的面试题。
解法1:一轮循环移位计数 (移位运算比除法运算效率要高,注意要考虑是负数的情况)
解法2:位运算
解法3:num &= num-1 巧妙之处在于,对高位没有影响。不断做 num &= num-1 直到num=0。
1010 & 1001 = 1000 1000 * 0111 = 0000
int one_appear_count_by_binary(int num){
int count = 0;
while(num !=0 ){
num &= num-1;
count++;
}
return count;
}
请定义一个宏,比较两个数a、b的大小,不能使用大于、小于、if语句
分析:
#define min(a,b) ((a)>(b)?(a):(b))
#define MIN(A,B) ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __a : __b; })
这里不能使用比较符号:
#define min(a,b) ((a)-(b) & (0x1<<31))?(a):(b)
把十进制数(long型)分别以二进制和十六进制形式输出,不能使用printf系列
分析:
char *integer_to_hex(long i); //eg: 20 => 14
char *integer_to_bin(long i); //eg: 20 => 10100
注意,转16进制中,要判断tmp[i]是否是有符号的数
tmp[i] = tmp[i]>=0 ? tmp[i] : tmp[i]+16;
ipv4 转 int
比如: 127.0.0.1 , 转为int 为 (01111111 00000000 00000000 00000001)
思路:
int toInt(){
}
那么,int 转 ipv4 如何解呢?
判断一个自然数是否是某个数的平方
说明:当然不能使用开方运算。
square(25) YES
square(35) NO
方法1: 从1开始遍历,显然这种方法很差 方法2: 除数跟余数比较,除数从2开始,每一轮都跟结果比较;相等就是存在这个数,不相等就把除数++;时间复杂度为(根号n)。在一个数比较大时,效率不够好。如1194877489 =(34567)^2,需要从2开始,一直比较到34566,做3万多次除法和比较运算。跟方法1一样。。
方法3:二分查找 O(logn)。比如25:
a. 先取(0+25)/2=12.5,12.512.5>25,因此这个数应该小于12.5 b.(0+12)/2 = 6, 66>25 c. (0+6)/2 = 3 d. (3+6)/2 = 4.5 e. (5+6)/2 = 5.5
int is_powered(int num)
1024! 末尾有多少个0?
分析: 末尾0的个数取决于2和5的个数 能被2整除的数比能被5整除的数要多得多,因此只统计被5整除的数的个数
编程实现两个正整数的除法(和取模)
编程实现两个正整数的除法,当然不能用除法操作符。
int div(const int x, const int y)
- 循环减被除数,减到不能再减,当除数很大,被除数小时,效率很低
- 位运算
求两个或N个数的最大公约数和最小公倍数。
大整数乘法(或 大整数阶乘)
请使用代码计算1234567891011121314151617181920*2019181716151413121110987654321 。
- 注意结果可能超出长整形的最大范围 2^64-1
- 采用分治算法,将大整数相乘转换为小整数计算
规律分析:任意位数的整数相乘,最终都可以转化为2位数相乘
两个数相乘,小数点后位数没有限制,请写一个高精度算法
数值的整数次方
题目:实现函数double Power(double base, int exponent),求base的exponent次方。
不需要考虑溢出。
分析:这是一道看起来很简单的问题。可能有不少的人在看到题目后30秒写出如下的代码:
double Power(double base, int exponent)
{
double result = 1.0;
for(int i = 1; i <= exponent; ++i)
result *= base;
return result;
}
上面的代码没有考虑: exponent<=0
判断一个浮点数是不是等于0时,不是直接写 base == 0 ,而应该判断它们的差的绝对值是不是小于一个很小的范围
如果指数大于0,我们还可以使用递归实现:a^n = a^(n/2)*a^(n/2) (n为偶数), 通过这个思路也可以实现
2^16 = 2^8 * 2^8
2^8 = 2^4 * 2^4
2^4 = 2^2 * 2^2
2^2 = 2^1 * 2^1
2^1 = 2
用例:
2 3 = 8
0 3 = 0
2 0 = 1
2 -3 = 1/(2^3) = 0.125
0 -3
使用递归实现的代码示例:
double Power(double base, unsigned int exponent)
{
if (exponent == 0) return 1;
if (exponent == 1) return base;
double result = Power(base, exponent >> 1);
result *= result;
if (exponent & 1) result = result*base;
return reslut;
}
求根号2的值
并且按照我的需要列出指定小数位,比如根号2是1.141 我要列出1位小数就是1.1 2位就是1.14, 1000位就是1.141...... 等。。
分析: 泰勒级数 牛顿迭代法
整数的素数和分解问题
歌德巴赫猜想说任何一个不小于6的偶数都可以分解为两个奇素数之和。 对此问题扩展,如果一个整数能够表示成两个或多个素数之和,则得到一个素数和分解式。
对于一个给定的整数,输出所有这种素数和分解式。 注意,对于同构的分解只输出一次(比如5只有一个分解2 + 3,而3 + 2是2 + 3的同构分解式
例如,对于整数8,可以作为如下三种分解:
(1) 8 = 2 + 2 + 2 + 2
(2) 8 = 2 + 3 + 3
(3) 8 = 3 + 5
大于K的最小正整数
给定一个集合A=0,1,3,8,指定任意一个正整数K,请用A中的元素组成一个大于K的最小正整数。
比如,A=[1,0] K=21 那么输出结构应该为100。
给定能随机生成整数1到5的函数,写出能随机生成整数1到7的函数。
设计一个随机算法
给你5个球,每个球被抽到的可能性为30、50、20、40、10,设计一个随机算法,该算法的输出结果为本次执行的结果。输出A,B,C,D,E即可。
构造一个随机发生器
已知一随机发生器,产生0的概率是p,产生1的概率是1-p,现在要你构造一个发生器, 使得它构造0和1的概率均为1/2;构造一个发生器,使得它构造1、2、3的概率均为1/3;..., 构造一个发生器,使得它构造1、2、3、...n的概率均为1/n,要求复杂度最低。
两个圆相交
两个圆相交,交点是A1,A2。现在过A1点做一直线与两个圆分别相交另外一点B1,B2。B1B2可以绕着A1点旋转。问在什么情况下,B1B2最长
输入四个点的坐标,求证四个点是不是一个矩形
关键点: 1.相邻两边斜率之积等于-1, 2.矩形边与坐标系平行的情况下,斜率无穷大不能用积判断。 3.输入四点可能不按顺序,需要对四点排序。
排列组合问题
1,2,3,4,5 五个不同的数字,打印不同的排列。这就是一个无向图的遍历,把每个数字看成一个节点。
用1、2、2、3、4、5这六个数字,写一个main函数,打印出所有不同的排列,
如:512234、412345 等,要求:"4"不能在第三位,"3"与"5"不能相连.
这是对上一题增加难度。但是需要
- 去掉 3,5之间的联通
- 2重复,过滤重复结果 treeset
- 4不能在3位