update linklist & numerical
This commit is contained in:
@@ -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值相同的结点删除。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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开始,
|
||||
于是运用题二的方法,我们找到它们的第一个交点即为所求。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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值相同的结点删除。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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 。另外只能输出结果,不能修改两个链表的数据。
|
||||
|
||||
|
||||
@@ -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位
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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整除的数的个数
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -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,要求复杂度最低。
|
||||
|
||||
|
||||
@@ -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米的环形跑道从同一地点同时同方向跑步,经过多少时间三人又同时从出发点出发?
|
||||
|
||||
|
||||
|
||||
@@ -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个。
|
||||
|
||||
@@ -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位
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user