update linklist & numerical

This commit is contained in:
ranwenjie
2021-09-09 13:48:07 +08:00
parent c21f1fe0a2
commit 7f2eace61c
11 changed files with 497 additions and 406 deletions
+25 -164
View File
@@ -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 。另外只能输出结果,不能修改两个链表的数据。
+14 -242
View File
@@ -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个。
+40
View File
@@ -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位