python-分治算法理解+练习

分治算法目录


一、分治算法是什么?

分治算法,就两个字:分和治。
分:通过一些规律把一个大问题分成若干小问题
治:把这些小问题以此解决,然后返回结果

举个例子:计算1-100的和,在没有求和公式的情况下都会从1+2+3+…+99+100。通过发现得到1+100=2+99=3+98…=49+
50,而这些我们就相当于把这个大问题换成了若干小问题。

二、实现步骤

1.二分法

上一篇提到的二分搜索其实就是实现分治算法的一种,可以说二分搜索是分治算法的一个子集;二分法的使用

2.递归

使用分治法最多的还是使用递归来解决问题。附上一篇关于递归的文章:递归讲解

3.合并排序,归并排序等…

三、使用要求

  1. 该问题的规模缩小到一定的程度就可以容易地解决

  2. 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质。

  3. 利用该问题分解出的子问题的解可以合并为该问题的解;

  4. 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。

四、练习

1.指数练习:

利用递归解决指数问题
def pow(x, n):
    if n <= 0:
        return 1
    elif n == 1:
        return x
    elif n % 2:
        return pow(x * x, n // 2) * x
    else:
        return pow(x * x, n // 2)

print(pow(5, 25))

2.查找任意一个峰值:

在一个数组中可能有多个峰值,请任意找一个并返回下标
def search(listt):
    return num(listt, 0, len(listt) - 1)


def num(listt, start, end):
    if start == end:
        return start
    elif start + 1 == end:
        if listt[start] > listt[end]:
            return start
        else:
            return end
    mid = (start + end) // 2
    if listt[mid - 1] < listt[mid] < listt[mid + 1]:
        return num(listt, mid + 1, end)
    elif listt[mid + 1] < listt[mid] < listt[mid - 1]:
        return num(listt, start, mid - 1)
    elif listt[mid] > listt[mid - 1] and listt[mid] > listt[mid + 1]:
        return mid


n = [0, 1, 9, 2, 3, 4, 8, 7, 5, 11, 6, 20, 23, 21]
print(search(n))

3.查找所有峰值:

def search(nums):
    i = 1
    index = []
    while i < len(nums):
        if nums[i - 1] < nums[i]and nums[i] > nums[i + 1]:
            index.append(i)
        i += 1
    return index

n = [0, 1, 9, 2, 3, 4, 8, 7, 5, 11, 6, 20, 23, 21]
print(search(n))

4.数组集合:

两个长短不一的数组找集合,可能会有重复的数字,将他们全部输出
def search(nums1, nums2):
    index = []
    i, j = 0, 0
    while True:
        if nums2[j] == nums1[i]:
            index.append(nums2[j])
            i += 1
            j += 1
        else:
            i += 1

        if i == len(nums1) - 1 or j == len(nums2) - 1:
            break
    return index


nums1 = [1, 2, 2, 2, 1]
nums2 = [2, 2, 3]
nums1.sort()
nums2.sort()

print(search(nums1, nums2))

5.计算逆序对:

在一个无序数组中 a[i]>a[j] 且 i<j 这两个数就是一个逆序对
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 right[j] < left[i]:
            result.append(right[j])
            j += 1
            inv_count += (len(left)-i)
    result += left[i:]
    result += right[j:]
    return result, inv_count


def conut(nums):
    if len(nums) < 2:
        return nums, 0
    mid = len(nums) // 2
    left, inv_left = conut(nums[:mid])
    right, inv_right = conut(nums[mid:])

    merged, counts = merge(left, right)
    counts += (inv_left + inv_right)
    return merged, counts


nums = [1, 20, 3, 5, 4]
print(conut(nums))

总结

提示:这里对文章进行总结:分治法作为三大算法之一,必有它的难点和独特之处。拿到题时多加思考和分析,理解+勤练习。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值