zoukankan      html  css  js  c++  java
  • 数据结构与算法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))
  • 相关阅读:
    JavaScript 为字符串添加样式 【每日一段代码80】
    JavaScript replace()方法 【每日一段代码83】
    JavaScript for in 遍历数组 【每日一段代码89】
    JavaScript 创建用于对象的模板【每日一段代码78】
    html5 css3 新元素简单页面布局
    JavaScript Array() 数组 【每日一段代码88】
    JavaScript toUTCString() 方法 【每日一段代码86】
    位运算
    POJ 3259 Wormholes
    POJ 3169 Layout
  • 原文地址:https://www.cnblogs.com/lvxiaoning/p/11638628.html
Copyright © 2011-2022 走看看