经典算法之分治

分治:将一个难以直接解决的大问题,分割成一些规模较小的相同问题,该问题的规模缩小到一定的程度就可以容易地解决,这些子问题互相独立且与原问题形式相同,以便各个击破,分而治之。

分治法一般算法框架(伪代码)

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)
}

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值