分治:将一个难以直接解决的大问题,分割成一些规模较小的相同问题,该问题的规模缩小到一定的程度就可以容易地解决,这些子问题互相独立且与原问题形式相同,以便各个击破,分而治之。
分治法一般算法框架(伪代码)
Divide-and-Conquer§
1. if |P|≤n0
2. then return(ADHOC§)
3. 将P分解为较小的子问题 P1 ,P2 ,…,Pk
4. for i=1 to k
5. do yi = Divide-and-Conquer(Pi) //递归解决Pi
6. T = MERGE(y1,y2,…,yk) //合并子问题
7. return(T)
其中|P|表示问题P的规模;n0为一阈值,表示当问题P的规模不超过n0时,问题已容易直接解出,不必再继续分解。ADHOC§是该分治法中的基本子算法,用于直接解小规模的问题P。因此,当P的规模不超过n0时直接用算法ADHOC§求解。算法MERGE(y1,y2,…,yk)是该分治法中的合并子算法,用于将P的子问题P1 ,P2 ,…,Pk的相应的解y1,y2,…,yk合并为P的解。
分治法的经典算法:(都很常见,就不写问题描述了)
704. 二分查找、合并排序、快速排序
二分查找代码:
func search(nums []int, target int) int {
start,end, mid := 0,len(nums)-1,0
if end < 0 || target > nums[end]{
return -1
}
for start <= end{
mid = (start+end)/2
if nums[mid] == target{
return mid
}
if nums[mid] > target{
end = mid - 1
}else{
start = mid+1
}
}
return -1
}
归并排序:
先将数组分成长度为length/2的子数组,再将子数组分成长度=length/4,继续划分,直到长度=1,进行合并,代码:
func MergeSort(arr *[]int){
if len(*arr) == 0{
return
}
mergeSortByLength(arr,0,len(*arr)-1)
}
func mergeSortByLength(arr *[]int,low,high int){
if low<high{
mid := (low+high)/2
mergeSortByLength(arr,low,mid)
mergeSortByLength(arr,mid+1,high)
merge(arr,low,mid,high)
}
}
func merge(arr *[]int,low,mid,high int){
var (
brr []int
i,j int = low,mid+1
)
for i<=mid && j<=high{
if (*arr)[i]<(*arr)[j]{
brr = append(brr,(*arr)[i])
i++
}else{
brr = append(brr,(*arr)[j])
j++
}
}
for i<=mid{
brr = append(brr,(*arr)[i])
i++
}
for j<= high{
brr = append(brr,(*arr)[j])
j++
}
for i:=0;i<len(brr);i++{
(*arr)[low] = brr[i]
low++
}
}
func TestMergeSort(){
var arr = []int{4,1,7,9,2,6,3,5,8}
MergeSort(&arr)
fmt.Println("归并:",arr)
}
快排:先找到一个基准,将基准左边的数组都小于基准,右边的数组都大于基准,再对左右两个子数组继续,找基准,分成两个子数组...
func QuickSort(arr *[]int){
if len(*arr) == 0{
return
}
quick(arr,0,len(*arr)-1)
}
func quick(arr *[]int,left,right int){
low,high := left,right
pivot := (*arr)[low]
for low < high{
for low<high && (*arr)[high] > pivot{
high --
}
if low < high{
(*arr)[low] = (*arr)[high]
low++
}
for low<high && (*arr)[low] < pivot{
low ++
}
if low < high{
(*arr)[high] = (*arr)[low]
high --
}
}
(*arr)[low] = pivot
if low - left > 1{
quick(arr,left,low-1)
}
if right-low > 1{
quick(arr,low+1,right)
}
}
func TestQuickSort(){
var arr = []int{7,9,1,4,2,5,3,6,8}
QuickSort(&arr)
fmt.Println("快排:",arr)
}