From 7f2eace61c5871419a1ccef14fd97372d6e2e854 Mon Sep 17 00:00:00 2001 From: ranwenjie Date: Thu, 9 Sep 2021 13:48:07 +0800 Subject: [PATCH] update linklist & numerical --- 9 Algorithms Job Interview/2 链表.md | 189 ++----------- 9 Algorithms Job Interview/2.1 链表-排序.md | 62 +++++ 9 Algorithms Job Interview/2.2 链表-删除.md | 62 +++++ 9 Algorithms Job Interview/2.3 链表-2条.md | 41 +++ 9 Algorithms Job Interview/4 数值问题.md | 256 +----------------- .../4.1 数值-加减乘除.md | 93 +++++++ 9 Algorithms Job Interview/4.2 数值-指数.md | 103 +++++++ 9 Algorithms Job Interview/4.3 数值-随机数.md | 21 ++ .../4.4 数值-最小公倍数.md | 25 ++ 9 Algorithms Job Interview/5 数组数列问题.md | 11 + 9 Algorithms Job Interview/97 其他.md | 40 +++ 11 files changed, 497 insertions(+), 406 deletions(-) create mode 100644 9 Algorithms Job Interview/2.1 链表-排序.md create mode 100644 9 Algorithms Job Interview/2.2 链表-删除.md create mode 100644 9 Algorithms Job Interview/2.3 链表-2条.md create mode 100644 9 Algorithms Job Interview/4.1 数值-加减乘除.md create mode 100644 9 Algorithms Job Interview/4.2 数值-指数.md create mode 100644 9 Algorithms Job Interview/4.3 数值-随机数.md create mode 100644 9 Algorithms Job Interview/4.4 数值-最小公倍数.md create mode 100644 9 Algorithms Job Interview/97 其他.md diff --git a/9 Algorithms Job Interview/2 链表.md b/9 Algorithms Job Interview/2 链表.md index d4d16a1..407d3b4 100644 --- a/9 Algorithms Job Interview/2 链表.md +++ b/9 Algorithms Job Interview/2 链表.md @@ -2,11 +2,14 @@ 链表常常碰到的问题有: + +* [链表排序](2.1%20链表-排序.md) +* [链表删除](2.2%20链表-删除.md) : 如删除链表中的p节点,在p节点前面插入节点q, 要求O(1)复杂度 +* [2个链表](2.3%20链表-2条.md) 相交,合并 * 链表反转 * 链表中是否有环 -* 删除链表中的p节点,在p节点前面插入节点q, 要求O(1)复杂度 -* 2个链表相交 -* 2个链表合并 + + 常用解题思路 @@ -15,22 +18,6 @@ * 快慢指针 -## 判断俩个链表是否相交 - -给出俩个单向链表的头指针,比如h1,h2,判断这俩个链表是否相交。为了简化问题,我们假设俩个链表均不带环。 - -问题扩展: - -1.如果链表可能有环列? -2.如果需要求出俩个链表相交的第一个节点列? - - -## 输出两个非降序链表的并集 - -请修改append函数,利用这个函数实现: - -两个非降序链表的并集,1->2->3 和 2->3->5 并为 1->2->3->5 。另外只能输出结果,不能修改两个链表的数据。 - ## 输出链表中倒数第k个结点 @@ -44,78 +31,31 @@ struct ListNode }; -## 链表排序 - -Given a head pointer pointing to a linked list ,please write a function that sort the list -in increasing order. You are not allowed to use temporary array or memory copy (微软面试题) - -``` -struct -{ - int data; - struct S_Node *next; -}Node; - -Node * sort_link_list_increasing_order (Node *pheader): -``` - -## 单链表归并排序 - -啥是归并排序? - - - -## 给定单链表,检测是否有环。 - - -``` -int isLinkCicle(Link *head); -``` - -解题思路 - -1. 暴力 -2. 空间换时间,用一个HashMap -3. 快慢指针: 使用两个指针p1,p2从链表头开始遍历,p1每次前进一步,p2每次前进两步。如果p2到达链表尾部,说明无环,否则p1、p2必然会在某个时刻相遇(p1==p2),从而检测到链表中有环。 - - - -类似的题有: - -1 给定两个单链表(head1, head2),检测两个链表是否有交点,如果有返回第一个交点。 - - 如果head1==head2,那么显然相交,直接返回head1。 - 否则,分别从head1,head2开始遍历两个链表获得其长度len1与len2,假设len1>=len2, -那么指针p1由head1开始向后移动len1-len2步,指针p2=head2, -下面p1、p2每次向后前进一步并比较p1p2是否相等,如果相等即返回该结点, -否则说明两个链表没有交点。 - - -2 给定单链表(head),如果有环的话请返回从头结点进入环的第一个节点。 - - 运用题一,我们可以检查链表中是否有环。如果有环,那么p1p2重合点p必然在环中。从p点断开环,方法为:p1=p, p2=p->next, -p->next=NULL。此时,原单链表可以看作两条单链表,一条从head开始,另一条从p2开始, -于是运用题二的方法,我们找到它们的第一个交点即为所求。 - - - -## 删除链表中的p节点 - -只给定单链表中某个结点p(并非最后一个结点,即p->next!=NULL)指针,删除该结点。 - -办法很简单,首先是放p中数据,然后将p->next的数据copy入p中,接下来删除p->next即可。 - - -类似的还有问题:只给定单链表中某个结点p(非空结点),在p前面插入一个结点。办法类似,首先分配一个结点q,将q插入在p后, -接下来将p中的数据copy入q中,然后再将要插入的数据记录在p中。都可以做到0(1)复杂度 - - ## 链表反转 三个指针,遍历一遍(0(n)复杂度 +## 从尾到头输出链表 + +输入一个链表的头结点,从尾到头反过来输出每个结点的值。链表结点定义如下: + +``` +struct ListNode{ + int m_nKey; + ListNode* m_pNext; +}; +``` + +思路一: 辅助栈,需要一个栈空间 +思路二: 反转链表,然后遍历 +思路三: 递归实现,将printf语句放在递归调用后面。果然妙极。。 + + + + + ## 复杂链表的复制 题目:有一个复杂链表,其结点除了有一个m_pNext指针指向下一个结点外,还有一个m_pSibling指向链表中的任一结点或者NULL。其结点的C++定义如下: @@ -133,85 +73,6 @@ struct ComplexNode -## 找出两个链表的第一个公共结点 - -题目:两个单向链表,找出它们的第一个公共结点。链表的结点定义为: -``` -struct ListNode -{ - int m_nKey; - ListNode* m_pNext; -}; -``` - -分析:第一个公共节点,也就是2个链表中的节点的m_pNext 指向的同一个节点。 - -1. 先遍历2个链表,得到各自的长度,和差sub -2. 长链表先遍历sub个节点,然后2个节点一起遍历 -3. 第一次同时指向的同一个节点就是这个commonNode - - - - -## 从尾到头输出链表 - -输入一个链表的头结点,从尾到头反过来输出每个结点的值。链表结点定义如下: - -``` -struct ListNode{ - int m_nKey; - ListNode* m_pNext; -}; -``` - -思路一: 辅助栈,需要一个栈空间 -思路二: 反转链表,然后遍历 -思路三: 递归实现,将printf语句放在递归调用后面。果然妙极。。 - - -## 在O(1)时间内删除链表结点 - -题目:给定链表的头指针和一个结点指针,在O(1)时间删除该结点。链表结点的定义如下: - -``` -struct ListNode{ - int m_nKey; - ListNode* m_pNext; -}; - -//函数的声明如下: -void deleteNode(ListNode* pListHead, ListNode* pToBeDeleted); - -``` - -思路: -保存下一个节点的值tmp,删除下一个节点,当前节点=tmp - - -## 将两链表中data值相同的结点删除 - - -有双向循环链表结点定义为: - - -``` -struct node{ - int data; - struct node *front,*next; -}; - -``` - -有两个双向循环链表A,B,知道其头指针为:pHeadA,pHeadB,请写一函数将两链表中data值相同的结点删除。 - - - - - - - - - diff --git a/9 Algorithms Job Interview/2.1 链表-排序.md b/9 Algorithms Job Interview/2.1 链表-排序.md new file mode 100644 index 0000000..f0f4288 --- /dev/null +++ b/9 Algorithms Job Interview/2.1 链表-排序.md @@ -0,0 +1,62 @@ +# 链表-排序 + + + + +## 链表排序 + +Given a head pointer pointing to a linked list ,please write a function that sort the list +in increasing order. You are not allowed to use temporary array or memory copy (微软面试题) + +``` +struct +{ + int data; + struct S_Node *next; +}Node; + +Node * sort_link_list_increasing_order (Node *pheader): +``` + + +## 单链表归并排序 + +啥是归并排序? + + + +## 给定单链表,检测是否有环。 + +``` +int isLinkCicle(Link *head); +``` + +解题思路 + +1. 暴力 +2. 空间换时间,用一个HashMap +3. 快慢指针: 使用两个指针p1,p2从链表头开始遍历,p1每次前进一步,p2每次前进两步。如果p2到达链表尾部,说明无环,否则p1、p2必然会在某个时刻相遇(p1==p2),从而检测到链表中有环。 + + + +类似的题有: + +1 给定两个单链表(head1, head2),检测两个链表是否有交点,如果有返回第一个交点。 + + 如果head1==head2,那么显然相交,直接返回head1。 + 否则,分别从head1,head2开始遍历两个链表获得其长度len1与len2,假设len1>=len2, +那么指针p1由head1开始向后移动len1-len2步,指针p2=head2, +下面p1、p2每次向后前进一步并比较p1p2是否相等,如果相等即返回该结点, +否则说明两个链表没有交点。 + + +2 给定单链表(head),如果有环的话请返回从头结点进入环的第一个节点。 + + 运用题一,我们可以检查链表中是否有环。如果有环,那么p1p2重合点p必然在环中。从p点断开环,方法为:p1=p, p2=p->next, +p->next=NULL。此时,原单链表可以看作两条单链表,一条从head开始,另一条从p2开始, +于是运用题二的方法,我们找到它们的第一个交点即为所求。 + + + + + diff --git a/9 Algorithms Job Interview/2.2 链表-删除.md b/9 Algorithms Job Interview/2.2 链表-删除.md new file mode 100644 index 0000000..082149b --- /dev/null +++ b/9 Algorithms Job Interview/2.2 链表-删除.md @@ -0,0 +1,62 @@ +#链表-删除 + + + +## 在O(1)时间内删除链表结点 + +题目:给定链表的头指针和一个结点指针,在O(1)时间删除该结点。链表结点的定义如下: + +``` +struct ListNode{ + int m_nKey; + ListNode* m_pNext; +}; + +//函数的声明如下: +void deleteNode(ListNode* pListHead, ListNode* pToBeDeleted); + +``` + +思路: +保存下一个节点的值tmp,删除下一个节点,当前节点=tmp + + + + +## 删除链表中的p节点 + +只给定单链表中某个结点p(并非最后一个结点,即p->next!=NULL)指针,删除该结点。 + +办法很简单,首先是放p中数据,然后将p->next的数据copy入p中,接下来删除p->next即可。 + + +类似的还有问题:只给定单链表中某个结点p(非空结点),在p前面插入一个结点。办法类似,首先分配一个结点q,将q插入在p后, +接下来将p中的数据copy入q中,然后再将要插入的数据记录在p中。都可以做到0(1)复杂度 + + + + +## 将两链表中data值相同的结点删除 + + +有双向循环链表结点定义为: + + +``` +struct node{ + int data; + struct node *front,*next; +}; + +``` + +有两个双向循环链表A,B,知道其头指针为:pHeadA,pHeadB,请写一函数将两链表中data值相同的结点删除。 + + + + + + + + + diff --git a/9 Algorithms Job Interview/2.3 链表-2条.md b/9 Algorithms Job Interview/2.3 链表-2条.md new file mode 100644 index 0000000..b80c6a6 --- /dev/null +++ b/9 Algorithms Job Interview/2.3 链表-2条.md @@ -0,0 +1,41 @@ +# 链表-2条 + + +## 找出两个链表的第一个公共结点 + +题目:两个单向链表,找出它们的第一个公共结点。链表的结点定义为: +``` +struct ListNode +{ + int m_nKey; + ListNode* m_pNext; +}; +``` + +分析:第一个公共节点,也就是2个链表中的节点的m_pNext 指向的同一个节点。 + +1. 先遍历2个链表,得到各自的长度,和差sub +2. 长链表先遍历sub个节点,然后2个节点一起遍历 +3. 第一次同时指向的同一个节点就是这个commonNode + + + + +## 判断俩个链表是否相交 + +给出俩个单向链表的头指针,比如h1,h2,判断这俩个链表是否相交。为了简化问题,我们假设俩个链表均不带环。 + +问题扩展: + +1.如果链表可能有环列? +2.如果需要求出俩个链表相交的第一个节点列? + + + +## 输出两个非降序链表的并集 + +请修改append函数,利用这个函数实现: + +两个非降序链表的并集,1->2->3 和 2->3->5 并为 1->2->3->5 。另外只能输出结果,不能修改两个链表的数据。 + + diff --git a/9 Algorithms Job Interview/4 数值问题.md b/9 Algorithms Job Interview/4 数值问题.md index b91be5c..60bedec 100644 --- a/9 Algorithms Job Interview/4 数值问题.md +++ b/9 Algorithms Job Interview/4 数值问题.md @@ -2,44 +2,26 @@ 这部分都是一些数学几何计算方面的问题。主要由: -* 位运算 +* [加减乘除](4.1%20数值-加减乘除.md) +* 指数(乘方) * 随机数 +* 进制转换:位运算 * 大数问题 -## 求1+2+…+n +## ipv4 转 int -要求不能使用乘除法、for、while、if、else、switch、case等关键字以及条件判断语句(A?B:C)。 +比如: 127.0.0.1 , 转为int 为 (01111111 00000000 00000000 00000001) -思路:这是等差数列求和公式, 1+2+3.......+N =(n+1)n/2 - -分析: -1. 不能使用循环,那就用递归 -2. 递归需要终止递归的条件判断语句,这里也不能用if,想其他办法,可以使用 &&逻辑与 运算符(在n>0条件满足是,才会指向后面的递归语句) +思路: ``` -int sum(n){ - int sum=0; - (n>0) && sum=n+factorial(n-1) - return sum; -} -``` +int toInt(){ - -## 大数阶乘(factorial) - -> 阶乘 n*(n-1)*(n-2)*...*1 - -主要考虑算出来的结果肯定会大于int表达的范围,这时候怎么处理? - -``` -int factorial(n){ - int sum=0; - (n>0) && sum=n+factorial(n-1) - return sum; } ``` +那么,int 转 ipv4 如何解呢? @@ -68,19 +50,6 @@ int one_appear_count_by_binary(int num){ ``` -## 请定义一个宏,比较两个数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系列 @@ -97,160 +66,26 @@ 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.5*12.5>25,因此这个数应该小于12.5 -b.(0+12)/2 = 6, 6*6>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? +## 请定义一个宏,比较两个数a、b的大小,不能使用大于、小于、if语句 分析: -末尾0的个数取决于2和5的个数 -能被2整除的数比能被5整除的数要多得多,因此只统计被5整除的数的个数 - - - -## 编程实现两个正整数的除法(和取模) - -编程实现两个正整数的除法,当然不能用除法操作符。 ``` -int div(const int x, const int y) +#define min(a,b) ((a)>(b)?(a):(b)) +#define MIN(A,B) ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __a : __b; }) ``` -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 +#define min(a,b) ((a)-(b) & (0x1<<31))?(a):(b) ``` -使用递归实现的代码示例: - -``` -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的偶数都可以分解为两个奇素数之和。 +> 歌德巴赫猜想说任何一个不小于6的偶数都可以分解为两个奇素数之和。 对此问题扩展,如果一个整数能够表示成两个或多个素数之和,则得到一个素数和分解式。 对于一个给定的整数,输出所有这种素数和分解式。 @@ -266,69 +101,6 @@ double Power(double base, unsigned int exponent) ``` -## 大于K的最小正整数 - -给定一个集合A=[0,1,3,8](该集合中的元素都是在0,9之间的数字,但未必全部包含),指定任意一个正整数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位 - - - - - - diff --git a/9 Algorithms Job Interview/4.1 数值-加减乘除.md b/9 Algorithms Job Interview/4.1 数值-加减乘除.md new file mode 100644 index 0000000..463fcb1 --- /dev/null +++ b/9 Algorithms Job Interview/4.1 数值-加减乘除.md @@ -0,0 +1,93 @@ +# 数值-加减乘除 + + + +## 求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 sum(n){ + int sum=0; + (n>0) && sum=n+factorial(n-1) + return sum; +} +``` + + + + +## 大数阶乘(factorial) + +> 阶乘 n*(n-1)*(n-2)*...*1 + +主要考虑算出来的结果肯定会大于int表达的范围,这时候怎么处理? + +``` +int factorial(n){ + int sum=0; + (n>0) && sum=n+factorial(n-1) + return sum; +} +``` + +考虑整数溢出情况 + +``` +char[] factorial(int n){ + int sum=0; + return sum; +} + +``` + + + +## 实现两个正整数的除法(和取模) + +编程实现两个正整数的除法,当然不能用除法操作符。 +``` +int div(const int x, const int y) +``` + +1. 循环减被除数,减到不能再减,当除数很大,被除数小时,效率很低 +2. 位运算 + + + + + +## 大整数乘法(或 大整数阶乘) + +请使用代码计算`1234567891011121314151617181920*2019181716151413121110987654321` 。 + +1. 注意结果可能超出长整形的最大范围 2^64-1 +2. 采用分治算法,将大整数相乘转换为小整数计算 + +规律分析:任意位数的整数相乘,最终都可以转化为2位数相乘 + + + +## 两个数相乘,小数点后位数没有限制,请写一个高精度算法 + + + + + + +## 1024! 末尾有多少个0? + +分析: +末尾0的个数取决于2和5的个数 +能被2整除的数比能被5整除的数要多得多,因此只统计被5整除的数的个数 + + + + + diff --git a/9 Algorithms Job Interview/4.2 数值-指数.md b/9 Algorithms Job Interview/4.2 数值-指数.md new file mode 100644 index 0000000..371b804 --- /dev/null +++ b/9 Algorithms Job Interview/4.2 数值-指数.md @@ -0,0 +1,103 @@ +# 4.2 数值-指数 + + +> 在a^n中,a叫做底数,n叫做指数。a^n读作“a的n次方”或“a的n次幂“ + + + +## 数值的整数次方 + +题目:实现函数`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...... 等。。 + +分析: +泰勒级数 +牛顿迭代法 + + + + + + +## 判断一个自然数是否是某个数的平方 + +说明:当然不能使用开方运算。 + +``` +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.5*12.5>25,因此这个数应该小于12.5 +b.(0+12)/2 = 6, 6*6>25 +c. (0+6)/2 = 3 +d. (3+6)/2 = 4.5 +e. (5+6)/2 = 5.5 + +``` +int is_powered(int num) +``` + + + diff --git a/9 Algorithms Job Interview/4.3 数值-随机数.md b/9 Algorithms Job Interview/4.3 数值-随机数.md new file mode 100644 index 0000000..fc74070 --- /dev/null +++ b/9 Algorithms Job Interview/4.3 数值-随机数.md @@ -0,0 +1,21 @@ +# 4.3 数值-随机数 + + + + +## 给定能随机生成整数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,要求复杂度最低。 + + diff --git a/9 Algorithms Job Interview/4.4 数值-最小公倍数.md b/9 Algorithms Job Interview/4.4 数值-最小公倍数.md new file mode 100644 index 0000000..7b835a1 --- /dev/null +++ b/9 Algorithms Job Interview/4.4 数值-最小公倍数.md @@ -0,0 +1,25 @@ +# 4.4 数值-最小公倍数 + + + +求两个或N个数的最大公约数和最小公倍数? + +> 最大公约数: 12、16的公约数有1、2、4,其中最大的一个是4,4是12与16的最大公约数 +> 最小公倍数: 45和30的最小公倍数是多少? +> 定理: (a,b)x[a,b]=ab ; (a,b) 是 a,b 的 最大公约数, [a,b]是a,b 的 最小公倍数 + + + +### 最小公倍数应用场景 + + +甲、乙、丙三人是朋友,他们每隔不同天数到图书馆去一次。甲3天去一次,乙4天去一次,丙5天去一次。有一天,他们三人恰好在图书馆相会,问至少再过多少天他们三人又在图书馆相会? + + +一块砖长20厘米,宽12厘米,厚6厘米。要堆成正方体至少需要这样的砖头多少块? + + +甲每秒跑3米,乙每秒跑4米,丙每秒跑2米,三人沿600米的环形跑道从同一地点同时同方向跑步,经过多少时间三人又同时从出发点出发? + + + diff --git a/9 Algorithms Job Interview/5 数组数列问题.md b/9 Algorithms Job Interview/5 数组数列问题.md index 9dcf99b..fad9f1d 100644 --- a/9 Algorithms Job Interview/5 数组数列问题.md +++ b/9 Algorithms Job Interview/5 数组数列问题.md @@ -66,6 +66,17 @@ int binary_search_lash(int *a,int length,int key); + +## 大于K的最小正整数 + +给定一个集合A=[0,1,3,8](该集合中的元素都是在0,9之间的数字,但未必全部包含),指定任意一个正整数K,请用A中的元素组成一个大于K的最小正整数。 + +比如,A=[1,0] K=21 那么输出结构应该为100。 + + + + + ## 查找最小的k个元素(top-k) 题目:输入n个整数,输出其中最小的k个。 diff --git a/9 Algorithms Job Interview/97 其他.md b/9 Algorithms Job Interview/97 其他.md new file mode 100644 index 0000000..28f2057 --- /dev/null +++ b/9 Algorithms Job Interview/97 其他.md @@ -0,0 +1,40 @@ +# 其他 + + + +## 两个圆相交 + +两个圆相交,交点是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位 + + + + +