分治算法其实很有趣(下)

简介: 分治法可能是最著名的通用算法设计技术了。虽然它的名气可能和它那好记的名字有关,但它的确是当之无愧:因为很多有效的算法实际上就是这个通用算法的特殊实现。

分治算法的应用


归并排序

归并排序是成功应用分治策略的一个完美例子,对于给定一组序列含 n 个数组 A[0..n-1],归并排序将其一分为二:A[0..n/2-1]A[n/2..n-1],并对每个子数组递归排序,然后将这两个排好序的子数组合并为一个有序数组。

image.png

Go 代码如下:

func mergeSort(items []int) []int {
    if len(items) < 2 {
        return items
    }
    first := mergeSort(items[:len(items)/2])
    second := mergeSort(items[len(items)/2:])
    return merge(first, second)
}

让我们先编写 mergeSort() 函数。它是一个递归函数,这意味着它会调用自己,在这种情况下,它实际上会调用自己两次。 mergeSort 函数的要点是将数组分成大致相等的两个部分,在这些部分上调用自身,然后调用 merge() 将这些部分重新组合在一起。


merge() 函数用于将两个排序列表合并回一个排序列表,这是真正发生“魔术”的地方。在递归的最低级别,两个“排序”列表的长度均为 1。这些单元素列表将合并为长度为 2 的排序列表,我们可以从那里构建。然后写出归并的 merge() 函数:

func merge(a []int, b []int) []int {
    final := []int{}
    i := 0
    j := 0
    for i < len(a) && j < len(b) {
        if a[i] < b[j] {
            final = append(final, a[i])
            i++
        } else {
            final = append(final, b[j])
            j++
        }
    }
    for ; i < len(a); i++ {
        final = append(final, a[i])
    }
    for ; j < len(b); j++ {
        final = append(final, b[j])
    }
    return final
}


然后在 main() 函数中验证:

func main() {
  unsorted := []int{8, 3, 2, 9, 7, 1, 5, 4}
  sorted := mergeSort(unsorted)
  fmt.Println(sorted)
  // sorted = [1, 2, 3, 4, 5, 6, 7, 8, 9]
}


image.png


二分查找

目的:在一个含有 N 个元素的有序数组中有效地的定位目标值。


思想:假设在有序数组 arr 中查找元素 k,返回 k 所在的下标(索引值)。设 arr[low,high] 是当前的查找区间,确定该区间的中间位置 mid=⌊(low+high)//2⌋ ,然后将待查的 k 值与 arr[mid] 比较:

  • k==arr[mid],说明找到 k,则查找成功并且终止,则找到该元素;
  • k<arr[mid],根据数组有序的前提,目标值 k 在左边的区域中,索引的范围改为 [low, mid-1]
  • k>arr[mid],目标值在右边的区域中,查找索引范围改为 [mid+1, high]


示例:

输入    nums = [-1,0,3,5,9,12], target = 9
输出    4
解释    9 出现在 nums 中并且下标为 4


Python 代码如下:

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left = 0
        right = len(nums) - 1
        # 在区间 [left, right] 内查找 target
        while left < right:
            # 取区间中间节点
            mid = left + (right - left) // 2
            # nums[mid] 小于目标值,排除掉不可能区间 [left, mid],在 [mid + 1, right] 中继续搜索
            if nums[mid] < target:
                left = mid + 1 
            # nums[mid] 大于等于目标值,目标元素可能在 [left, mid] 中,在 [left, mid] 中继续搜索
            else:
                right = mid
        # 判断区间剩余元素是否为目标元素,不是则返回 -1
        return left if nums[left] == target else -1

其他应用


快速排序也是另一种基于分治算法的重要排序算法,不像归并排序是按照元素数组中的位置对它们进行划分,快速排序是按照元素的值对它们进行划分。


二叉树遍历中前序、中序和后序遍历都可以用到分治,因为二叉树本身的定义就是将同样类型的树分为两个更小的组成部分——左子树和右子树。


其他如大整数乘法和 Strassen 矩阵乘法也可以巧妙的运用分治算法来获得更好的渐近效率,感兴趣的读者可以继续探索。

相关文章
|
6月前
|
人工智能 自然语言处理 算法
当prompt策略遇上分治算法,南加大、微软让大模型炼成“火眼金睛”
【2月更文挑战第24天】当prompt策略遇上分治算法,南加大、微软让大模型炼成“火眼金睛”
55 2
当prompt策略遇上分治算法,南加大、微软让大模型炼成“火眼金睛”
|
6月前
|
算法
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-分治算法
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-分治算法
51 0
|
6月前
|
存储 缓存 算法
【数据结构与算法】【小白也能学的数据结构与算法】递归 分治 迭代 动态规划 无从下手?一文通!!!
【数据结构与算法】【小白也能学的数据结构与算法】递归 分治 迭代 动态规划 无从下手?一文通!!!
|
4月前
|
算法 开发者 Python
惊呆了!Python算法设计与分析,分治法、贪心、动态规划...这些你都会了吗?不会?那还不快来学!
【7月更文挑战第10天】探索编程巅峰,算法至关重要。Python以其易读性成为学习算法的首选。分治法,如归并排序,将大问题拆解;贪心算法,如找零问题,每步求局部最优;动态规划,如斐波那契数列,利用子问题解。通过示例代码,理解并掌握这些算法,提升编程技能,面对挑战更加从容。动手实践,体验算法的神奇力量吧!
72 8
|
4月前
|
算法 Python
算法不再难!Python分治法、贪心、动态规划实战解析,轻松应对各种算法挑战!
【7月更文挑战第8天】掌握Python算法三剑客:分治、贪心、动态规划。分治如归并排序,将大问题拆解递归解决;贪心策略在每步选最优解,如高效找零;动态规划利用子问题解,避免重复计算,解决最长公共子序列问题。实例展示,助你轻松驾驭算法!**
67 3
|
3月前
|
算法 搜索推荐
算法设计 (分治法应用实验报告)基于分治法的合并排序、快速排序、最近对问题
这篇文章是关于分治法应用的实验报告,详细介绍了如何利用分治法实现合并排序和快速排序算法,并探讨了使用分治法解决二维平面上的最近对问题的方法,包括伪代码、源代码实现及时间效率分析,并附有运行结果和小结。
|
4月前
|
算法 Python
Python算法高手进阶指南:分治法、贪心算法、动态规划,掌握它们,算法难题迎刃而解!
【7月更文挑战第10天】探索Python算法的精华:分治法(如归并排序)、贪心策略(如找零钱问题)和动态规划(解复杂问题)。通过示例代码揭示它们如何优化问题解决,提升编程技能。掌握这些策略,攀登技术巅峰。
110 2
|
4月前
|
算法 程序员 Python
算法小白到大神的蜕变之路:Python分治法、贪心、动态规划,一步步带你走向算法巅峰!
【7月更文挑战第9天】探索算法之旅,以Python解锁编程高手之路。分治法如二分查找,将复杂问题拆解;贪心算法解决活动选择,每次选取局部最优;动态规划求斐波那契数列,避免重复计算,实现全局最优。每一步学习,都是编程能力的升华,助你应对复杂挑战,迈向算法大师!
46 1
|
4月前
|
存储 算法 Python
Python算法界的秘密武器:分治法巧解难题,贪心算法快速决策,动态规划优化未来!
【7月更文挑战第9天】Python中的分治、贪心和动态规划是三大关键算法。分治法将大问题分解为小问题求解,如归并排序;贪心算法每步选局部最优解,不保证全局最优,如找零钱;动态规划存储子问题解求全局最优,如斐波那契数列。选择合适算法能提升编程效率。
65 1
|
4月前
|
存储 算法 Python
震撼!Python算法设计与分析,分治法、贪心、动态规划...这些经典算法如何改变你的编程世界!
【7月更文挑战第9天】在Python的算法天地,分治、贪心、动态规划三巨头揭示了解题的智慧。分治如归并排序,将大问题拆解为小部分解决;贪心算法以局部最优求全局,如Prim的最小生成树;动态规划通过存储子问题解避免重复计算,如斐波那契数列。掌握这些,将重塑你的编程思维,点亮技术之路。
70 1