数学算法思想

算法思想

公式拆分 :  

P9231 [蓝桥杯 2023 省 A] 平方差(拆分问题)-CSDN博客

Note:        得到 x=(y−z)×(y+z),可知 x满足可以拆成 2个奇偶性相同的数的乘积。

可图性判断:

可图性判断(图论)-CSDN博客

Note:        重复移除度序列中的最大值并减少相应数量的其他度值

若最终序列中所有数值都减至零,则说明该序列是可图的,反之若出现负数则不可图。

def havel_hakimi(sequence):
    while True:
        # 移除序列中所有的0并排序
        
        if not sequence:
            # 所有元素处理完毕且不含负数,序列可图
        
        n = sequence.pop(0)  # 移除并获取第一个元素
        if n > len(sequence):
            # 如果n大于序列的长度,无法继续,序列不可图
        
        # 从序列的剩余部分中减去1
        for i in range(n):
            sequence[i] -= 1
            if sequence[i] < 0:
                # 如果出现负数,序列不可图

双指针遍历:

双指针遍历(找最大值)-CSDN博客

局部最优解导向全局最优解: 每次移动较短的板,尝试找到一个更高的板,这样在减少宽度的同时,有机会增加高度,从而找到一个可能更大的容器。因为如果移动较长的板,高度不会增加,而宽度减少

def max_water_container(height):
    # 初始化左右指针

    # 当左右指针未相遇时
    while left < right:
        # 计算当前容器能盛放的水量
        water = min(height[left], height[right]) * (right - left)
        
        # 更新最大水量
        max_water = max(max_water, water)

        # 移动指向较短板的指针
        if height[left] < height[right]:
            left += 1
        else:
            right -= 1

    # 返回计算出的最大水量
    return max_water

前缀和:

P8649 [蓝桥杯 2017 省 B] k 倍区间(前缀和+优化(桶分类))_p8649 [蓝桥杯 2017 省 b] k 倍区间 题解-CSDN博客

Note:        首先滑动窗口计算各前缀和取模K,计算同余两前缀和之差(为K的倍数)的个数

main(){
    while(temp)
        sum = (sum + temp) % k;
		count1[sum]++;

	// 单一前缀和为k的倍数(特判)
	ans += (count1[0] * (count1[0] + 1) / 2)

    for (int i = 1; i < k; i++)
		// 单一前缀和,不为k的倍数
		ans += (count1[i] * (count1[i] - 1) / 2);
}

素数判断:

欧拉筛法优化(判断素数)-CSDN博客

Note:        利用定理筛选:素数只存在6的倍数附近(即6k+1,6k-1)

                 再用遍历范围5~sqrt(num),+=6验证

二分查找:

      求方程单解:

二分查找算法-CSDN博客

Note:        二分搜索逼近给定方程的解 x ,直到得到的解与目标值的差值满足特定的精度要求

# 初始化 x, (min, max)为解的范围    eg.(0,100)
x = (min_val + max_val) / 2

sum_val = x * (3 + x * (2 + x * (7 + 8 * x))) + 6
#  二分查找逼近精度
while abs(sum_val - y) > 1e-3:
    # 如果 sum 小于 y
    if sum_val < y:
        min_val = x
        x = (max_val + x) / 2
    else:
        max_val = x
        x = (min_val + x) / 2

    # 重新计算 sum
    sum_val = x * (3 + x * (2 + x * (7 + 8 * x))) + 6

方程多解: 

二分查找,求方程多解-CSDN博客

Note:        循环遍历可能的区间,判断区间内是否存在解,二分法逼近解

def f(n):
    # 定义多项式函数
    return a * n**3 + b * n**2 + c * n + d

def find_roots():
    s = 0  # 记录找到的解的个数
    for i in range(-100, 100):
        min_val = i
        max_val = i + 1
        
        # 判断左端点是否为零点,若是解加一
        if f(min_val) == 0:
            continue
        
        # 判断区间内是否存在解,若有解加一
        if f(min_val) * f(max_val) < 0:
            # 逼近于实际值
            while max_val - min_val > 1e-5:
                mid = (min_val + max_val) / 2
                # 若端点积大于0
                if f(mid) * f(max_val) > 0:
                    max_val = mid
                else:
                    min_val = mid
            s += 1
         if (s == 3)
            break;

枚举:

枚举算法思想-CSDN博客

Note:    通过三层升序嵌套循环(其中 j 从 i 开始,k 从 j 开始),当前值的平方和小于输入的 n

函数 寻找四个数(n):
    对于 i 从 0 到 满足 sq(i) < n 执行循环:
        对于 j 从 i 到 满足 sq(i) + sq(j) < n 执行循环:
            对于 k 从 j 到 满足 sq(i) + sq(j) + sq(k) < n 执行循环:
                计算 l = sqrt(n - sq(i) - sq(j) - sq(k))
                如果 l 是整数:
                    如果 sq(i) + sq(j) + sq(k) + sq(l) 等于 n:
                        输出结果 (i, j, k, l)
                        返回
    输出未找到结果

排序:

字典序:

P1012 [NOIP1998 提高组] 拼数( 字典序 )-CSDN博客

Note:        转数字为string,利用字典序判断最大拼数

cmp(){
    // 规定字典序顺序
    return (a+b)>(b+a)
}
main(){
    利用cmp排序数字(转换为string)
     
    返回的拼接后所有数字
}

快排:

快速排序(按从小到大排)-CSDN博客

Note:选择基准元素,分区左为小于基准,右为大于基准,并递归对子数组进行排序。

分区操作结束时,left指针的位置实际上是在或右侧的第一个大于或等于基准值的位置

def quicksort(arr, low, high):
    if low < high:
        # 执行分区操作,找到基准元素的正确位置
        pivot_index = partition(arr, low, high)
        
        # 对基准左侧的子数组进行快速排序
        quicksort(arr, low, pivot_index - 1)
        
        # 对基准右侧的子数组进行快速排序
        quicksort(arr, pivot_index + 1, high)

def partition(arr, low, high):
    # 选择最后一个元素作为基准
    left = low
    right = high - 1
    
    while True:
        # 左指针向右移动,直到找到大于等于pivot的元素

        # 右指针向左移动,直到找到小于等于pivot的元素

        if left < right:
            # 如果左指针仍在右指针左侧,交换两个元素
        else:
            # 否则,分区操作完成
            break

    # 将基准元素移至正确位置
    arr[left], arr[high] = arr[high], arr[left]
    return left

桶排序:

(桶排序)-CSDN博客

Note:         

  • 数据分布均匀时最为有效。
  • 当有合理的方法来选择桶的数量和范围时。
  • 对于小范围的整数排序,桶排序非常有效
std::vector<double> bucket_sort(std::vector<double>& arr) {
    std::vector<std::vector<double>> buckets(n);
    
    // 将数组中的数分配到各个桶中
    
    // 对每个桶进行排序

    // 合并桶中的元素
    std::vector<double> result;
    
    return result;
}

计算:

快速幂算法:

快速幂算法(数论)-CSDN博客

Note:         指数奇数时乘底数,指数偶数时乘底数的一半幂

def recursive_quick_power(a, b):
    if b == 0:
        return 1
    if b % 2 == 1:
        return (a * recursive_quick_power(a, b - 1))
    else:
        half = recursive_quick_power(a, b // 2)
        return (half * half)

 累计加法: 

累计加法(数学)-CSDN博客

Note:        排序后,计算每个点突出的部分,最后计算下面共有的部分 

def calculate_histogram_area(heights):
    # 1. 排序柱子
    heights.sort()
    
    # 2. 逐步计算突出的部分
    for height in heights:
        # 计算当前柱子突出的部分并累加到总面积中
        total_area += (height - previous_height) * (len(heights) - 1)
        previous_height = height
    
    # 3. 计算下方共有的矩形面积
    bottom_area = sum(heights) * (heights[-1] - heights[0])  # 下方共有矩形面积
    total_area += bottom_area  # 加上下方共有的矩形面积
    
    return total_area

倍数判断: 

K倍判断(巧用大整数取模定理)-CSDN博客

Note:         二维数组 s[len][k] = {0} (用于存储余数出现的次数(代替哈希表))

// len为前数扩展的位数,k为扩展后的取模K

对于 i 从 0 到 n-1:
    // 扩展arr[i]数位(0~11)
    对于 len 从 0 到 11: 
       // 更新K
       // 更新s[len][K]

对于 i 从 0 到 n-1:
    t = arr[i] % k
    len = 数字 arr[i] 的位数    (也就是前数需要扩展的位数)
    // count加上相补的余数出现次数
    count += s[len][(k - t) % k]

    // 如果与本身匹配,count减一

输出 count

数学规律:

大数运算:

计算n的n次方的个位数(利用规律图)_求n的n次方的个位数,-CSDN博客

Note:       利用周期为4的规律和N的个位数,计算幂的个位数

def last_digit_of_power(num):
    # 计算次方数的周期

    # 获取num的个位数

    # 如果n的n次方可以被4整除,将n设为4(特殊情况)

    # 初始化结果为1
    result = 1
    # 按周期进行乘法,模拟次方计算
    for _ in range(n):
        result *= last_digit
        # 保证结果为个位数
        result %= 10

    return result

  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值