Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
public
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
daijian
public
Commits
a7db8908
Commit
a7db8908
authored
Jan 14, 2021
by
彭凯
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Upload New File
parent
00ecb840
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
150 additions
and
0 deletions
+150
-0
二分法.md
+150
-0
No files found.
二分法.md
0 → 100644
View file @
a7db8908
#### 二分法
#### 二分法
二分法,是一种常用的查找算法,主要针对于有序数组,用二分法的最大好处是每查找一次就可以扔掉一半的数据,从而大大减少需要查找的总数据,进而提高查找速度。
> 对于区间[a,b]上连续不断且f(a)·f(b)<0的函数y=f(x),通过不断地把函数f(x)的零点所在的区间一分为二,使区间的两个端点逐步逼近零点,进而得到零点近似值的方法叫二分法。
>
> [百度百科词条]([https://baike.baidu.com/item/%E4%BA%8C%E5%88%86%E6%B3%95/1364267?fr=aladdin](https://baike.baidu.com/item/二分法/1364267?fr=aladdin))
下面是二分法的一个简单的实现
```
python
# 给定一个数组,元素按照正序排列,范围为1-100
# 查找43是否在该数组中,如果是,返回它的索引;如果不是,返回-1
class
Solution
():
# 暴力法,遍历整个数组
def
search
(
self
,
nums
,
target
):
n
=
len
(
nums
)
if
n
==
0
:
return
-
1
for
i
in
range
(
n
):
if
nums
[
i
]
==
target
:
return
i
return
-
1
# 二分法
def
dichotomy
(
self
,
nums
,
target
):
n
=
len
(
nums
)
if
n
==
0
:
return
-
1
left
,
right
=
0
,
n
-
1
while
left
<=
right
:
medium
=
(
left
+
right
)
//
2
if
nums
[
medium
]
==
target
:
return
medium
elif
nums
[
medium
]
<
target
:
left
=
medium
+
1
elif
target
<
nums
[
medium
]:
right
=
medium
-
1
return
-
1
s
=
Solution
()
print
(
s
.
search
([
i
for
i
in
range
(
1
,
101
)],
43
))
print
(
s
.
dichotomy
([
i
for
i
in
range
(
1
,
101
)],
43
))
```
#### 二分法的刨析与变种
二分法看似简单,很容易被理解,而且使用也较为平凡,但是你是否想过为什么它只对有序数组有效呢?
其实,二分的原理就在于二分,即它每次都能找到一个有序数组最中间的那个数字,这个数字具有以下两个特征
-
比最左边的数字小
-
比最右边的数字大
明白了这一点之后,就可以阅读二分法的进阶方法了,现有如下的一个题目
> 假设按照升序排序的数组在预先未知的某个点上进行了旋转。
>
> ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
>
> 搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
>
> 你可以假设数组中不存在重复的元素。
>
对于这个题目,看到了
**按照升序排序**
应该很自然的联想到二分法查找。但是这个题目有一个不同之处在于它并不是全排序的二分排序,那么可以很自然的想到:先将它转换成为一个全排序的有序数组,再进行查找。除此之外,利用暴力法也可以解决本题,只是耗时比较大,现将两种方法展示如下
```
python
# 暴力法
class
Solution
:
def
search
(
self
,
nums
,
target
):
for
num
in
nums
:
if
num
==
target
:
return
nums
.
index
(
target
)
return
-
1
```
采用先将数组转换为有序数组之后,再进行二分查找
```
python
# 先排序,再进行二分查找
class
Solution
:
def
search
(
self
,
nums
,
target
):
tmp
=
[]
# 这里要使用深拷贝,要不然之后求得的索引会出错
# 这与Python自身的语言特点有关
tmp
[:]
=
nums
tmp
.
sort
()
left
,
right
=
0
,
len
(
nums
)
-
1
while
left
<=
right
:
medium
=
(
left
+
right
)
//
2
if
target
==
tmp
[
medium
]:
return
nums
.
index
(
target
)
elif
target
<
tmp
[
medium
]:
right
=
medium
-
1
else
:
left
=
medium
+
1
return
-
1
```
直接二分法,根据之前讲到的二分法的数字特征,可以直接使用二分法,分析与算法步骤如下
-
数组是有序的,只是从某个位置进行了一次旋转,那么一定存在一段有序的数字,即以数组中间的数为界,左半边或者右半边必定有序,原因是旋转数组相当于交换某两个部分,可以自己多写几组实验一下
-
由于数组一定存在某一部分有序,即可能是左半部分有序,也可能是有半部分有序。此时,有序的这半部分就可以构造二分查找
-
当左半部分有序时,那么数组中间的数一定有如下特征
-
比最左边的数字大
-
比该有序部分的最后一个数小
根据该特征,可以判断出目标值是否在该范围:如果在,则缩小右边界到数组中间的数;如果不在,则到右半部分进行查找
-
当右半部分有序时,那么数组中间的数一定有如下特征
-
比该有序部分的第一个数字大
-
比最右边的数字小
根据该特征,可以判断出目标值是否在该范围:如果在,则缩小左边界到数组中间的数;如果不在,则到左半部分进行查找
```
python
# 变种二分法
class
Solution
:
def
search
(
self
,
nums
,
target
):
if
not
nums
:
return
-
1
left
,
right
=
0
,
len
(
nums
)
-
1
while
left
<=
right
:
medium
=
(
left
+
right
)
//
2
# 中间值就是要查找的值
if
nums
[
medium
]
==
target
:
return
medium
# 左半部分有序
elif
nums
[
0
]
<=
nums
[
medium
]:
# 在该范围
if
nums
[
0
]
<=
target
<
nums
[
medium
]:
right
=
medium
-
1
# 不在该范围
else
:
left
=
medium
+
1
# 右半部分有序
else
:
# 在该范围
if
nums
[
medium
]
<
target
<=
nums
[
len
(
nums
)
-
1
]:
left
=
medium
+
1
# 不在该范围
else
:
right
=
medium
-
1
return
-
1
```
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment