• 数据结构与算法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))

     练习5:加和值最大的子序列问题

      在一个一维数组中找到连续的子序列,且这个子序列的和加值最大

      例如,一个数组序列为-2,1,-3,4,-1,2,1,-5,4

      则这个序列对应的加和值最大的子序列为4,-1,2,1,加和值为6

    def subarray2(alist):    #动态规划
        result = 0
        local = 0
        for i in alist:
            local = max(local + i, i)
            result = max(result, local)
        return result
    
    def subarray1(alist):       #分治法
        return subarray1_helper(alist, 0, len(alist)-1)
    def subarray1_helper(alist, left, right):
        if(left == right):
            return alist[left]
        mid = (left + right) // 2
        return max(subarray1_helper(alist, left, mid),
                   subarray1_helper(alist, mid+1, right),
                   max_cross(alist, left, mid, right))
    def max_cross(alist, left, mid, right):
        sum = 0
        left_sum = 0
        for i in range(mid, left-1,-1):
            sum += alist[i]
            if(sum > left_sum):
                left_sum = sum
        sum = 0
        right_sum = 0
        for i in range(mid+1, right+1):
            sum += alist[i]
            if(sum > right_sum):
                right_sum = sum
        return left_sum + right_sum
    
    alist = [-1, 2, -2, 5, -4, 3, 7]
    print(subarray1(alist))

    练习:6:水槽问题

      给定一个容量为C升的水槽,初始时给这个水槽装满水。每天都会给水槽中加入I升的水,若有溢出,则舍弃多余的水。另外在第i天,水槽中有i升的水会被喝掉,请计算在哪一天水槽的水被用完。

    def water_problem(C, I):
        i = 1
        day = 0
        while(C > I):
            C = min(C - i + I, C)
            day += 1
            i += 1
        return day
    C, I = 5, 2
    print(water_problem(C, I))

    练习7:奇-偶数换序问题

      给定一个含有2n个元素的数组,形式如{a1,a2,a3,...,b1,b2,...bn},按照{a1,b1,a2,b2,...,an,bn}排序

      举例:

        输入:arr[] = {1,2,9,15}

        输出:1 9 2 15   

        输入:arr[] = {1,2,3,4,5,6}

        输出:1 4 2 5 3 6

    def Shuffle_Array(alist, left, right):
        if(left == right -1):
            return
        mid = (left + right) // 2
        mmid = (left + mid) // 2
        temp = mid + 1
        for i in range(mmid + 1, mid + 1):
            alist[i], alist[temp] = alist[temp], alist[i]
            temp += 1
        Shuffle_Array(alist, left, mid)
        Shuffle_Array(alist, mid+1, right)
    
    a = [1,3,5,7,2,4,6,8]
    Shuffle_Array(a,0, len(a)-1)
    for i in range(len(a)):
        print(a[i], end=" ")

    练习8:用最少的步数收集所有硬币

      给定几摞硬币,这些硬币相邻排列,我们用最少的步数收集所有的硬币,其中每一步可以沿水平线或者垂直线连续收集

      举例:

      输入:height[] = [2 1 2 5 1]

      数组中每个值代表对应摞的高度,此处给了我们5摞硬币,其中第一摞有2个硬币,第二摞有1个硬币,其余依次对应。

      输出:4

    def min_Steps(height):
        def min_Steps_helper(height, left, right, h):
            if left >= right:
                return 0
            m = left
            for i in range(left, right):
                if height[i] < height[m]:
                    m = i
            return min(right - left,
                       min_Steps_helper(height, left, m, height[m])+
                       min_Steps_helper(height, m + 1, right, height[m])+
                       height[m] - h)
        return min_Steps_helper(height, 0, len(height), 0)
    height = [2,1,2,5,1]
    print(min_Steps(height))
  • 相关阅读:
    select和epoll的区别
    Epoll导致的selector空轮询
    2.集合框架中的泛型有什么优点?
    java的语法基础(二)
    17-文本属性和字体属性
    15-浮动
    16-margin的用法
    14-块级元素和行内元素
    12-简单认识下margin
    day15 什么是递归/递归与回溯
  • 原文地址:https://www.cnblogs.com/lvxiaoning/p/11638628.html
Copyright © 2020-2023  润新知