当前位置: 首页 > article >正文

高级算法分析与设计-分治法

一、分治法

1.逆序对的数目

def merge_and_count(nums, temp_arr, left, mid, right):
    """
    在合并过程中计数逆序对。
    :param nums: 原始数组
    :param temp_arr: 辅助数组
    :param left: 左子数组起始点
    :param mid: 左子数组与右子数组分界点
    :param right: 右子数组结束点
    :return: 当前合并步骤中逆序对的数量
    """
    i = left    # Starting index for left subarray
    j = mid + 1 # Starting index for right subarray
    k = left    # Starting index to be sorted
    inv_count = 0
    
    while i <= mid and j <= right:
        if nums[i] <= nums[j]:
            temp_arr[k] = nums[i]
            i += 1
        else:
            temp_arr[k] = nums[j]
            inv_count += (mid-i + 1)
            j += 1
        k += 1

    while i <= mid:
        temp_arr[k] = nums[i]
        i += 1
        k += 1

    while j <= right:
        temp_arr[k] = nums[j]
        j += 1
        k += 1

    for i in range(left, right + 1):
        nums[i] = temp_arr[i]
        
    return inv_count


def merge_sort_and_count(nums, temp_arr, left, right):
    """
    使用递归来执行归并排序并在排序过程中计数逆序对。
    :param nums: 原始数组
    :param temp_arr: 辅助数组
    :param left: 排序起始点
    :param right: 排序结束点
    :return: 总逆序对的数量
    """
    inv_count = 0
    if left < right:
        mid = (left + right)//2

        inv_count += merge_sort_and_count(nums, temp_arr, left, mid)
        inv_count += merge_sort_and_count(nums, temp_arr, mid + 1, right)

        inv_count += merge_and_count(nums, temp_arr, left, mid, right)

    return inv_count


def count_inversions(nums):
    """
    计算给定数组中的逆序对数量。
    :param nums: 整数数组
    :return: 逆序对数量
    """
    temp_arr = [0]*len(nums)
    return merge_sort_and_count(nums, temp_arr, 0, len(nums) - 1)


# 输入接口
if __name__ == "__main__":
    user_input = input()
    # 去掉中括号并分割字符串
    nums_str = user_input.strip('[]')
    nums = list(map(int, nums_str.split(',')))
    print(count_inversions(nums))




2.快速幂计算

def fast_pow(a, b):
    """
    使用分治法计算 a 的 b 次方(快速幂算法)。
    
    参数:
        a (float): 底数。
        b (int): 指数,可以是正数、负数或 0。
    
    返回:
        float: a 的 b 次方的值。
    """
    # 处理负数幂
    if b < 0:
        return 1 / fast_pow(a, -b)
    
    # 边界条件
    if b == 0:
        return 1.0  # 返回浮点数 1.0
    if b == 1:
        return a
    
    # 分治法递归计算
    half = fast_pow(a, b // 2)  # 计算 a^(b//2)
    
    # 如果 b 是偶数
    if b % 2 == 0:
        return half * half
    # 如果 b 是奇数
    else:
        return half * half * a

# 输入接口
if __name__ == "__main__":
    base_input = input()
    exponent_input = input()
    
    try:
        a = float(base_input)
        b = int(exponent_input)
        result = fast_pow(a, b)
        print(result)
    except ValueError:
        print("输入无效,请确保底数是浮点数,指数是整数。")




# # 输入接口
# if __name__ == "__main__":
#     user_input = input()
#     print(fast_pow(user_input))

3.众数

from collections import Counter

def find_modes(s):
    """
    找出多重集合 S 中的众数及其重数。
    
    参数:
        s (list): 包含元素的列表。
    
    返回:
        tuple: 众数及其重数。
    """
    # 统计每个元素的出现次数
    count = Counter(s)
    
    # 找到最大重数
    max_count = max(count.values())
    
    # 找到所有具有最大重数的元素
    modes = [num for num, freq in count.items() if freq == max_count]
    
    return modes, max_count


# 输入接口
if __name__ == "__main__":
    user_input = input()
    s = list(map(int, user_input.split()))
    
    modes, max_count = find_modes(s)
    print()
    for mode in modes:
        print(mode)
    print(max_count)




 4.最大子序和

def max_crossing_sum(nums, left, mid, right):
    """
    计算跨越中间点的最大子数组和。
    
    参数:
        nums (list): 包含整数的列表。
        left (int): 左边界索引。
        mid (int): 中间索引。
        right (int): 右边界索引。
    
    返回:
        int: 跨越中间点的最大子数组和。
    """
    # 包括中间点左边的最大子数组和
    left_sum = float('-inf')
    sum = 0
    for i in range(mid, left - 1, -1):
        sum += nums[i]
        if sum > left_sum:
            left_sum = sum
    
    # 包括中间点右边的最大子数组和
    right_sum = float('-inf')
    sum = 0
    for i in range(mid + 1, right + 1):
        sum += nums[i]
        if sum > right_sum:
            right_sum = sum
    
    return left_sum + right_sum

def max_subarray_sum_divide_and_conquer(nums, left, right):
    """
    使用分治算法计算具有最大和的连续子数组,并返回其最大和。
    
    参数:
        nums (list): 包含整数的列表。
        left (int): 左边界索引。
        right (int): 右边界索引。
    
    返回:
        int: 最大子数组和。
    """
    # 基本情况:只有一个元素
    if left == right:
        return nums[left]
    
    mid = (left + right) // 2
    
    # 递归计算左半部分的最大子数组和
    left_sum = max_subarray_sum_divide_and_conquer(nums, left, mid)
    
    # 递归计算右半部分的最大子数组和
    right_sum = max_subarray_sum_divide_and_conquer(nums, mid + 1, right)
    
    # 计算跨越中间点的最大子数组和
    cross_sum = max_crossing_sum(nums, left, mid, right)
    
    # 返回三者中的最大值
    return max(left_sum, right_sum, cross_sum)

def find_max_subarray_sum(nums):
    """
    找到具有最大和的连续子数组,并返回其最大和。
    
    参数:
        nums (list): 包含整数的列表。
    
    返回:
        int: 最大子数组和。
    """
    if not nums:
        return 0
    
    return max_subarray_sum_divide_and_conquer(nums, 0, len(nums) - 1)

# 输入接口
if __name__ == "__main__":
    user_input = input()
    nums = list(map(int, user_input.split()))
    
    result = find_max_subarray_sum(nums)
    print(result)




 5.求中位数

def partition(arr, low, high):
    """
    分区操作,将数组分区并返回枢轴位置。
    
    参数:
        arr (list): 包含整数的列表。
        low (int): 起始索引。
        high (int): 结束索引。
    
    返回:
        int: 枢纽位置。
    """
    pivot = arr[high]
    i = low - 1
    
    for j in range(low, high):
        if arr[j] <= pivot:
            i += 1
            arr[i], arr[j] = arr[j], arr[i]
    
    arr[i + 1], arr[high] = arr[high], arr[i + 1]
    return i + 1

def quickselect(arr, low, high, k):
    """
    快速选择算法,用于查找第 k 小的元素。
    
    参数:
        arr (list): 包含整数的列表。
        low (int): 起始索引。
        high (int): 结束索引。
        k (int): 查找第 k 小的元素。
    
    返回:
        int: 第 k 小的元素。
    """
    if low == high:
        return arr[low]
    
    pivot_index = partition(arr, low, high)
    
    if k == pivot_index:
        return arr[k]
    elif k < pivot_index:
        return quickselect(arr, low, pivot_index - 1, k)
    else:
        return quickselect(arr, pivot_index + 1, high, k)

def find_median(arr):
    """
    找到数组的中位数。
    
    参数:
        arr (list): 包含整数的列表。
    
    返回:
        int: 数组的中位数。
    """
    n = len(arr)
    if n % 2 == 1:
        # 奇数长度,直接找中间的那个
        return quickselect(arr, 0, n - 1, n // 2)
    else:
        # 偶数长度,返回第 [n/2] 大的元素
        return quickselect(arr, 0, n - 1, n // 2)

# 输入接口
if __name__ == "__main__":
    user_input = input()
    nums = list(map(int, user_input.split()))
    
    median = find_median(nums)
    print(median)




6.集合划分问题

def stirling_second_kind(n, m):
    """
    计算第二类斯特林数 S(n, m),表示将 n 个元素划分为 m 个非空子集的方法数。
    
    参数:
        n (int): 元素数量。
        m (int): 子集数量。
    
    返回:
        int: 第二类斯特林数 S(n, m)。
    """
    # 创建一个二维数组来存储中间结果
    dp = [[0] * (m + 1) for _ in range(n + 1)]
    
    # 设置边界条件
    dp[0][0] = 1
    
    # 填充 dp 数组
    for i in range(1, n + 1):
        for j in range(1, m + 1):
            dp[i][j] = j * dp[i - 1][j] + dp[i - 1][j - 1]
    
    return dp[n][m]

# 输入接口
if __name__ == "__main__":
    user_input = input()
    n, m = map(int, user_input.split())
    
    result = stirling_second_kind(n, m)
    print(result)





http://www.kler.cn/a/569435.html

相关文章:

  • 一个py文件搞定mysql查询+Json转换+表数据提取+根据数据条件生成excel文件+打包运行一条龙
  • Spring MVC框架六:Ajax技术
  • Redis面试常见问题——使用场景问题
  • React Portals深度解析:突破组件层级的渲染艺术
  • spring boot打包插件的问题
  • 【Mac】git使用再学习
  • Django应用的高级配置和管理
  • 【Python 数据结构 3.顺序表】
  • python | 2 个删除列表中空字符串元素的方法
  • 【GenBI优化】提升text2sql准确率:建议使用推理大模型,增加重试
  • The First项目报告:VANA如何重塑数据所有权与AI训练
  • Linux上用C++和GCC开发程序实现两个不同PostgreSQL实例下单个数据库中多个Schema稳定高效的数据迁移到其它PostgreSQL实例
  • Redis100道高频面试题
  • python-leetcode 46.从前序与中序遍历序列构造二叉树
  • 西电应用密码学与网络安全实验通关指南
  • Git与GitHub:它们是什么,有什么区别与联系?
  • coze生成的工作流,发布后,利用cmd命令行执行。可以定时发日报,周报等。让他总结你飞书里面的表格。都可以
  • C++对象特性
  • 1.Qt写简单的登录界面(c++)
  • Java---入门基础篇(下)---方法与数组