数据结构与算法6 - 分治法(上)

分治法:

1. 将问题拆分为几个子问题,并且这些子问题和原问题相似只是量级上小一些。

2. 递归地解决每一个子问题,然后结合这些子问题的解决方案构造出原问题的解决方案。

我们已经遇到过的问题:

  1. 二分搜索

  2. 归并排序

  3. 快速排序

分治法例子:

练习1:快速指数:

  能够快速计算出a的n次方

def Fast_pow(a, n):
    if n == 0:
        return 1.0
    elif n < 0:
        return 1 / Fast_pow(a, -n)
    elif n % 2:                             # 奇数
        return Fast_pow(a * a, n // 2) * a
    else:                                   # 偶数
        return Fast_pow(a * a, n // 2)
print(Fast_pow(2, 5))

练习2:搜索峰值

  数组中没有重复数,但可能存在多个峰值,返回任意一个峰值的index

  You may imagine that num[-1] = num[n] = -∞.

def search_peak(alist):
    return peak_helper(alist, 0, len(alist) - 1)

def peak_helper(alist, start, end):
    if start == end:
        return start

    if (start + 1 == end):
        if alist[start] > alist[end]:
            return start
        return end

    mid = (start + end) // 2
    if alist[mid] > alist[mid - 1] and alist[mid] > alist[mid + 1]:
        return mid
    if alist[mid - 1] > alist[mid] and alist[mid] > alist[mid + 1]:
        return peak_helper(alist, start, mid - 1)
    return peak_helper(alist, mid + 1, end)

alist = [1, 2, 4, 4, 2, 5, 2]
print(search_peak(alist)+1)

练习3: 两数组交集:

  给出2个大小不一的数组,找出这两个数组的交集

  要求:输出中不能有重复

  give nums1 = [1 2 2 1], nums2 = [2, 2], return[2]

def find_extra_fast(arr1, arr2):
    index = len(arr2)
    # left and right are end points denoting
    # the current range.
    left, right = 0, len(arr2) - 1
    while (left <= right):
        mid = (left + right) // 2;

        # If middle element is same of both
        # arrays, it means that extra element
        # is after mid so we update left to mid+1
        if (arr2[mid] == arr1[mid]):
            left = mid + 1

        # If middle element is different of the
        # arrays, it means that the index we are
        # searching for is either mid, or before
        # mid. Hence we update right to mid-1.
        else:
            index = mid
            right = mid - 1;

    # when right is greater than left our
    # search is complete.
    return index

练习4: 计算逆序对

  对数组做逆序对计数 - 距离数组的排序结果还有多远。如果一个数组已经排好序,那么逆序对个数为0

  在形式上,如果有两个元素a[i], a[j],如果a[i]>a[j],且i<j,那么a[i],a[j]构成一个逆序对

  例如序列2,4,1,3,5, 有三个逆序对,分别为(2,1),(4,1),(4,3)

def merge(left, right):
    result = list()
    i,j = 0,0
    inv_count = 0
    while i < len(left) and j < len(right):
        if left[i] < right[j]:
            result.append(left[i])
            i += 1
        elif left[i] > right[j]:
            result.append(right[j])
            j += 1
            inv_count += len(left) - i
    result += left[i:]
    result += right[j:]
    return result, inv_count

def count_invert(nums):
    if len(nums) < 2:
        return nums, 0
    mid = len(nums)//2
    left, inv_left = count_invert(nums[:mid])
    right, inv_right = count_invert(nums[mid:])
    merged, count = merge(left, right)
    count += (inv_left + inv_right)
    return merged, count
arr = [1, 20, 4, 6, 5]
print(count_invert(arr))

原文地址:https://www.cnblogs.com/lvxiaoning/p/11638628.html

时间: 2024-10-09 22:33:44

数据结构与算法6 - 分治法(上)的相关文章

常见数据结构与算法整理总结(上)

数据结构是以某种形式将数据组织在一起的集合,它不仅存储数据,还支持访问和处理数据的操作.算法是为求解一个问题需要遵循的.被清楚指定的简单指令的集合.下面是自己整理的常用数据结构与算法相关内容,如有错误,欢迎指出. 为了便于描述,文中涉及到的代码部分都是用Java语言编写的,其实Java本身对常见的几种数据结构,线性表.栈.队列等都提供了较好的实现,就是我们经常用到的Java集合框架,有需要的可以阅读这篇文章.Java - 集合框架完全解析 一.线性表 1.数组实现 2.链表 二.栈与队列 三.树

【算法】分治法细则

分治法的基本步骤:1.分解问题(Divide):把原问题分解为若干个与原问题性质相类似的子问题;2.求解字问题(Conquer):不断分解子问题并求解;3.合并子问题的解(Combine). 分治法的运用条件:1.原问题可以分解为若干与原问题的解:2.子问题可以分解并可以求解:3.子问题的解可以合并为原问题的解:4.分解后的子问题应互相独立,即不包含重叠子问题(如菲不那切竖列). 求解递归函数的方法: 1.代换法1)猜测解的行为:2)数学归纳法证明. 2.递归树法在递归树中,每一个结点都代表递归

[算法]:分治法-求大整数相乘

#问题大整数相乘 #思路说明 对于大整数计算,一般都要用某种方法转化,否则会溢出.但是python无此担忧了. Python支持**"无限精度"的整数,**一般情况下不用考虑整数溢出的问题,而且Python Int类型与任意精度的Long整数类可以无缝转换,超过Int 范围的情况都将转换成Long类型. 例如: >>> 2899887676637907866*1788778992788348277389943 51872581574157002360341697913

常用算法之分治法与动态规划法

之所以把这两种算法放到一起,是因为它们都是用来求最优解的问题,与贪心算法是不同的.但是这两种算法又有一些区别,下面来做解释: 分治,即分而治之,把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题--直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并.     上图用一个例子来解释如下: 当n>1时,想求得T(n),必须知道T(n-1),以此类推,所以要想求得T(n)就必须将T(n)分解,从最小的子问题开始计算,最终求得T(n),这个过程就是一个递归.分治与

算法题|-分治法解决最大子数组问题

分治法就是将一个复杂难解决问题拆成一些容易解决的小问题,再依次解决而最终解决整个问题 new int[] { 2, -3, 4, 67, 6 } 这样一个下标为0到4的数组,要找最大子数组,需要将其拆分成两个子数组,mid=(0+4)/2 即为0~mid的左数组和mid+1~4的右数组 最大子数组可能会出现在以下三个地方 左数组中的某个最大子数组 右数组中的某个最大子数组 以mid为界,向左找到一个最大数组,向右找到一个最大数组,将两个数组合并 第三种情况非常容易得到,通过遍历查找就可以解决,而

js算法:分治法-棋盘覆盖

在一个 2^k * 2^k 个方格组成的棋盘中,若恰有一个方格与其他方格不同.则称该方格为一特殊方格,称该棋盘为一特殊棋盘.显然特殊方格在棋盘上出现的位置有 4^k 种情形.因而对不论什么 k>=0 .有 4^k 种不同的特殊棋盘. 下图所看到的的特殊棋盘为 k=2 时 16 个特殊棋盘中的一个. 在棋盘覆盖问题中,要用下图中 4 中不同形态的 L 型骨牌覆盖一个给定的特殊棋牌上除特殊方格以外的全部方格,且不论什么 2 个 L 型骨牌不得重叠覆盖. 易知,在不论什么一个 2^k * 2^k 的棋

算法学习~分治法~快速排序

天天都在排序..简直就是要给这个混乱的世界一个正确的秩序..不过嘛.排序也有快慢之分, 冒泡排序法,,思路很简单就是一个个上去打擂台,,这样的时间复杂度很糟糕,,O(N^2)中O是一个常数,O(N^2)是指最大上限(估值)n(n-1)/2 = (n^2 - n)/2最高位估值仍为n^2两种情况是一样的. 选择排序法,,每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最前(最后),直到全部待排序的数据元素排完.选择排序是不稳定的排序方时间复杂度为O(n),最坏情况下

数据结构和算法之——二分查找上

二分查找(Binary Search)的思想非常简单,但看似越简单的东西往往越难掌握好,想要灵活运用就更加困难. 1. 二分查找的思想? 生活中二分查找的思想无处不在.一个最常见的就是猜数游戏,我随机写一个 0 到 99 的数,然后你来猜我写的是什么.猜的过程中,我会告诉你每次是猜大了还是猜小了,直到猜中为止.假如我写的数是 23,猜数过程如下所示. 最多只需要 7 次就猜出来了,这个过程是很快的.同理,要查找某个数据是否在给定的数组中,我们同样也可以利用这个思想. 二分查找针对的是一个有序的数

学好数据结构和算法 —— 非线性结构(上)

序言 上篇讲到线性结构,和线性结构相反的是非线性结构,非线性结构特点是一个结点元素可能有多个直接前驱和多个直接后继.常见的非线性结构有:二(多)维数组.树.图. 本来计划是非线性结构作为一篇,写着写着发现内容确实太多了,拆分为上.中.下3篇比较合适,所以改变了之前的计划. 1.二维数组 如:a[0][0]在水平方向有后继a[0][1],垂直方向有后继a[1][0],二维数组从水平方向或垂直方向看,某个元素都有前驱或后继,并不是线性结构. 二维数组的表示方法 矩阵表示法 行向量表示法 列向量表示法