Files
Learn-Algorithms/9 Algorithms Job Interview/4 数值问题.md
T
2021-09-08 00:45:07 +08:00

7.8 KiB
Raw Blame History

数值问题

这部分都是一些数学几何计算方面的问题。主要由:

  • 位运算
  • 随机数
  • 大数问题

求1+2+…+n

要求不能使用乘除法、for、while、if、else、switch、case等关键字以及条件判断语句(A?B:C)。

思路:这是等差数列求和公式, 1+2+3.......+N =(n+1)n/2

分析:

  1. 不能使用循环,那就用递归
  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) 
  1. 循环减被除数,减到不能再减,当除数很大,被除数小时,效率很低
  2. 位运算

求两个或N个数的最大公约数和最小公倍数。

大整数乘法(或 大整数阶乘)

请使用代码计算1234567891011121314151617181920*2019181716151413121110987654321 。

  1. 注意结果可能超出长整形的最大范围 2^64-1
  2. 采用分治算法,将大整数相乘转换为小整数计算

规律分析:任意位数的整数相乘,最终都可以转化为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"不能相连.

这是对上一题增加难度。但是需要

  1. 去掉 3,5之间的联通
  2. 2重复,过滤重复结果 treeset
  3. 4不能在3位