1. 二分查找
二分法是查找元素在一个有序列表中的位置的算法
联系场景:
- 通讯录查找一个人
- 给定一个数字,给他划分档位
首先想到的可能会使遍历,遍历所有的人,所有的档位,最差的情况从头遍历到尾部,也就是n个元素遍历n次,
二分法是范围取一半,通过比较大小来判断进入的位置,这也是为什么要有序.
那么二分法最差能进行多少次呢?
元素数量为n,我们进行一次模拟:
次数为x,
| 次数x | 剩余的元素数 |
|---|---|
| 1 | n/2 |
| 2 | n/2/2 |
| 3 | n/2/2/2 |
| 4 | n/2/2/2/2 |
| x | n/(2^x) |
最终剩余元素数为1时候就是我们找到该元素的时候, 2^x=n 求解x的值log2n,通过这个我们看出,遍历的话他的 数量增加速度是y=x是线性的, 而二分法是log2n是对数,增速较慢
练习:
php:
<?php
function findPos($arr,$target){
$first_index = 0;
$last_index = count($arr)-1;
$flag = false;
while($first_index <= $last_index){
$mid = ceil(($first_index+$last_index)/2);
if ($arr[$mid]==$target){
$flag = $mid;
return [
"res"=>true,
"index"=>$mid
];
}else if($arr[$mid]<$target){
$first_index=$mid+1;
}else{
$last_index = $mid-1;
}
}
return [
"res"=>false
];
}
$arr = [1,2,3,4];
$target = 1;
$res = findPos($arr,$target);
var_dump($res);
golang:
package main
import "fmt"
func findPos(num []int, target int) (res bool, pos int) {
first_index := 0
last_index := len(num) - 1
for {
if first_index <= last_index {
mid := (int)((last_index + first_index) / 2)
if num[mid] == target {
return true, mid
} else if num[mid] > target {
last_index = mid - 1
} else {
first_index = mid + 1
}
} else {
return false, 0
}
}
}
func main() {
num := []int{1, 2, 3, 4, 5, 6}
target := 2
res, index := findPos(num, target)
fmt.Println(res, index)
}
python:
import math
def findPos(lists,target):
first_index=0
last_index = len(lists)-1
while(first_index<=last_index):
mid=math.ceil((first_index+last_index)/2)
if lists[mid]==target:
return mid
elif lists[mid]<target:
first_index = mid+1
else:
last_index=mid-1
return None
lists =[1,2,3,4]
target=2
res=findPos(lists,target)
if not res is None:
print("找到了,位置是:"+str(res))
2. 大O表示法
大O表示法可以理解成算法的求导, 算法的运行时间以不同的速度在增加,大O表示法,表示的是比较的程序运行的次数,大O表示法表示的是最差情况下的操作数.
常见的大O运行的时间:
- O(logn) 对数时间, 二分法查找
- O(n) 线性时间, 快速排序算法
- O(n2) 选择排序
- O(n!)
3.旅行商问题
旅行商要去5个城市,要算出所有排列的长度,然后挑选出最短的,所以算法就是5x4x3x2x1 这个也就是O(n!)