大家好,欢迎来到IT知识分享网。
一、二分法
二分法是一种常用的查找算法,它基于有序列表的前提,将列表一分为二,确定目标值位于哪个子列表中,然后继续对该子列表进行二分查找,直到找到目标值或确定目标值不存在。
实现二分法的基本思路是:
- 确定有序列表的起始和结束位置;
- 取中间位置的值,并与目标值进行比较;
- 如果中间位置的值等于目标值,则返回该位置;
- 如果中间位置的值大于目标值,则在左侧子列表中继续查找;
- 如果中间位置的值小于目标值,则在右侧子列表中继续查找;
- 重复步骤2~5,直到找到目标值或确定目标值不存在。
下面是一个简单的 Python 实现:
def binary_search(arr, target): # 确定有序列表的起始和结束位置 left, right = 0, len(arr) - 1 # 重复步骤2~5,直到找到目标值或确定目标值不存在 while left <= right: # 取中间位置的值 mid = (left + right) // 2 # 如果中间位置的值等于目标值,则返回该位置 if arr[mid] == target: return mid # 如果中间位置的值大于目标值,则在左侧子列表中继续查找 elif arr[mid] > target: right = mid - 1 # 如果中间位置的值小于目标值,则在右侧子列表中继续查找 else: left = mid + 1 # 如果确定目标值不存在,则返回 -1 return -1
在这个实现中,函数 binary_search
接受一个有序列表 arr
和一个目标值 target
作为参数。它首先确定了列表的起始和结束位置,然后在循环中执行二分查找的步骤。如果找到目标值,则返回其位置;否则,返回 -1 表示目标值不存在于列表中。
二、三分法
三分法是一种求解单峰函数极值(最大值或最小值)的数值方法。其基本思想是将区间按照三等分划分,然后根据函数值的大小关系判断极值可能存在的区间,并缩小搜索区间的范围。通过不断缩小区间范围,最终可以找到单峰函数的极值点。
三分法的实现过程如下:
- 确定初始搜索区间 [a, b],其中 a 和 b 分别为区间左右端点。
- 计算区间的中点 m1 和 m2,即将区间 [a, b] 分成三等分,其中 m1 = (2a + b) / 3,m2 = (a + 2b) / 3。
- 分别计算函数在 m1 和 m2 处的取值 f(m1) 和 f(m2)。
- 根据 f(m1) 和 f(m2) 的大小关系,可以确定极值点可能存在的区间:
- 若 f(m1) > f(m2),则极值点可能存在于区间 [a, m2],因为 m1 已经被排除掉了;
- 若 f(m1) < f(m2),则极值点可能存在于区间 [m1, b],因为 m2 已经被排除掉了;
- 若 f(m1) = f(m2),则极值点可能存在于区间 [m1, m2],因为两端点都有可能成为极值点。
- 根据确定的区间,缩小搜索范围,并重复上述步骤,直到满足精度要求或达到最大迭代次数为止。
三分法的时间复杂度为 O(log(n)),其中 n 为精度要求需要的迭代次数。三分法比二分法的迭代次数更少,但每次迭代需要计算两个函数值,因此总的计算量可能更大。
以下是 Python 代码实现三分法:
def ternary_search(f, a, b, eps=1e-9, max_iters=200): """ 用三分法求解函数 f 在区间 [a, b] 上的极值点(最大值或最小值)。 Args: f: 待求解的函数,接受一个实数作为输入,返回一个实数作为输出。 a, b: 搜索区间的左右端点。 eps: 求解精度,当区间长度小于该值时停止搜索,默认值为 1e-9。 max_iters: 最大迭代次数,默认值为 200。 Returns: 极值点的坐标 x 和函数在该点的取值 y。 """ for i in range(max_iters): m1 = a + (b - a) / 3 m2 = b - (b - a) / 3 f1 = f(m1) f2 = f(m2) if f1 < f2: a = m1 else: b = m2 if abs(b - a) < eps: x = (a + b) / 2 y = f(x) return x, y x = (a + b) / 2 y = f(x) return x, y
这个函数接受一个函数 f,以及搜索区间的左右端点 a 和 b。可选参数包括求解精度 eps 和最大迭代次数 max_iters。函数返回极值点的坐标 x 和函数在该点的取值 y。
三、尺取法
尺取法是一种古老而实用的算法,用于解决一些与线性或区间相关的问题,如在一条直线或线段上确定一些满足特定条件的点或区间。尺取法的基本思想是使用两个指针(即“尺子”),将它们在待处理的序列上滑动,通过移动指针和比较序列元素来解决问题。
尺取法的具体步骤通常如下:
- 初始化左右指针,将它们都指向序列的起始位置。
- 滑动右指针,直到找到满足条件的区间或元素。
- 滑动左指针,直到不满足条件为止,同时记录当前区间或元素的解。
- 重复步骤2和3,直到右指针到达序列的末尾。
尺取法的时间复杂度通常是O(n),其中n是序列的长度。尺取法常用于解决一些算法竞赛中的问题,例如UVa Online Judge(一个著名的算法竞赛平台)上的一些问题。
下面是一个用Python实现尺取法的示例代码,该代码演示了如何在一个有序的整数序列中找到和为特定值的所有区间:
def find_subarrays(nums, target_sum): left, right, curr_sum = 0, 0, 0 res = [] while right < len(nums): # 滑动右指针,增加当前区间的和 curr_sum += nums[right] # 如果当前区间的和超过目标和,滑动左指针缩小区间 while curr_sum > target_sum and left <= right: curr_sum -= nums[left] left += 1 # 如果当前区间的和等于目标和,记录当前区间的左右端点 if curr_sum == target_sum: res.append((left, right)) # 滑动右指针继续扩大区间 right += 1 return res
这个函数的参数是一个有序的整数序列nums
和一个目标和target_sum
,它会返回所有和为target_sum
的子序列的左右端点。在函数内部,我们初始化左指针left
、右指针right
和当前区间的和curr_sum
,并在一个循环中不断滑动右指针right
,同时更新当前区间的和。如果当前区间的和超过了目标和,我们就滑动左指针left
,缩小区间。如果当前区间的和等于目标和,我们就记录当前区间的左右端点。最后,函数返回所有符合要求的区间。
四、前缀和
1.一维前缀和
前缀和算法是一种用于快速计算数组前缀和的算法。前缀和,指的是数组中从起点到当前位置的元素和。例如,对于数组A = [1, 2, 3, 4, 5],它的前缀和数组为prefixSum = [1, 3, 6, 10, 15]。
前缀和算法的思想很简单,就是用一个数组来存储原始数组的前缀和,可以用以下公式来计算:
prefixSum[i] = prefixSum[i-1] + nums[i]
其中,nums是原始数组,prefixSum是前缀和数组,i是当前位置。
使用前缀和算法可以在O(1)的时间内计算数组任意区间的和,只需要用区间右端点的前缀和减去区间左端点的前缀和即可。这种方法可以在一些需要频繁查询数组区间和的算法中得到应用,比如动态规划、数据结构等。
以下是用 Python 实现前缀和算法的代码:
def prefix_sum(nums): prefixSum = [0] * len(nums) prefixSum[0] = nums[0] for i in range(1, len(nums)): prefixSum[i] = prefixSum[i-1] + nums[i] return prefixSum
这段代码接收一个数组 nums
,并返回其前缀和数组 prefixSum
。算法的思路就是按照公式依次计算每个位置的前缀和。首先,创建一个与原数组长度相同的数组 prefixSum
,用来存储前缀和。然后,将第一个元素的前缀和赋值为原数组的第一个元素。接着,从第二个元素开始,通过遍历原数组,利用公式 prefixSum[i] = prefixSum[i-1] + nums[i]
计算当前位置的前缀和。最后,返回前缀和数组 prefixSum
。
2.二维前缀和
二维前缀和算法(也称为二维积分图像算法或二维累加和算法)是一种用于快速计算二维矩阵(也称为二维数组或图像)区域和的算法。该算法的时间复杂度为O(1),因此对于大型矩阵和需要频繁查询区域和的应用程序,它是一种非常有用的算法。
该算法的基本思想是首先计算出原始矩阵的每个元素到其左上角的所有元素的总和,然后使用这些总和计算出任意矩形区域的总和。这个过程可以通过一个递归式来实现:假设矩阵M的左上角是原点(0,0),则定义S(i,j)为子矩阵M(0,0)到M(i,j)的总和。可以使用以下公式来计算S(i,j):
S(i,j) = M(i,j) + S(i-1,j) + S(i,j-1) – S(i-1,j-1)
其中,M(i,j)是原始矩阵中第i行第j列的元素,S(i,j)是子矩阵M(0,0)到M(i,j)的总和,S(i-1,j)是子矩阵M(0,0)到M(i-1,j)的总和,S(i,j-1)是子矩阵M(0,0)到M(i,j-1)的总和,S(i-1,j-1)是子矩阵M(0,0)到M(i-1,j-1)的总和。
使用这个递归式,可以计算出整个矩阵的二维前缀和。一旦计算完成,就可以使用以下公式来计算任意矩形区域的总和:
sum(x1,y1,x2,y2) = S(x2,y2) – S(x1-1,y2) – S(x2,y1-1) + S(x1-1,y1-1)
其中,sum(x1,y1,x2,y2)是从原始矩阵中左上角为(x1,y1)、右下角为(x2,y2)的矩形区域的总和,S(x2,y2)是子矩阵M(0,0)到M(x2,y2)的总和,S(x1-1,y2)是子矩阵M(0,0)到M(x1-1,y2)的总和,S(x2,y1-1)是子矩阵M(0,0)到M(x2,y1-1)的总和,S(x1-1,y1-1)是子矩阵M(0,0)到M(x1-1,y1-1)的总和。
通过这些公式,可以高效地计算出任意矩形区域的总和,从而实现
各种二维矩阵问题的解决,例如图像处理、计算机视觉、地理信息系统等等。二维前缀和算法还可以扩展到更高维度的矩阵,如三维矩阵和四维矩阵。
具体来说,二维前缀和算法的步骤如下:
- 用原始矩阵M创建一个同样大小的矩阵S,并将S的所有元素初始化为0。
- 对于矩阵M中的每个元素M(i,j),计算S(i,j)的值。这可以通过使用递归式S(i,j) = M(i,j) + S(i-1,j) + S(i,j-1) – S(i-1,j-1)来完成。从左上角开始逐行、逐列地计算S的所有元素。
- 一旦计算完成,就可以使用sum(x1,y1,x2,y2) = S(x2,y2) – S(x1-1,y2) – S(x2,y1-1) + S(x1-1,y1-1)公式计算任意矩形区域的总和。
二维前缀和算法的时间复杂度为O(n^2),其中n是矩阵的大小。这是由于需要遍历整个矩阵并计算每个元素的前缀和。一旦前缀和被计算出来,计算任意矩形区域的总和所需的时间就是O(1)了。
总的来说,二维前缀和算法是一种高效的算法,可以快速计算二维矩阵区域和,这在许多应用程序中都非常有用。
以下是Python中的二维前缀和算法的代码实现:
def compute_prefix_sum(matrix): # 创建一个同样大小的矩阵S,并将S的所有元素初始化为0 rows, cols = len(matrix), len(matrix[0]) prefix_sum = [[0] * cols for _ in range(rows)] # 计算每个位置的前缀和 for i in range(rows): for j in range(cols): # 递推公式: S(i,j) = M(i,j) + S(i-1,j) + S(i,j-1) - S(i-1,j-1) prefix_sum[i][j] += matrix[i][j] if i > 0: prefix_sum[i][j] += prefix_sum[i-1][j] if j > 0: prefix_sum[i][j] += prefix_sum[i][j-1] if i > 0 and j > 0: prefix_sum[i][j] -= prefix_sum[i-1][j-1] return prefix_sum def query_sum(prefix_sum, x1, y1, x2, y2): # 使用前缀和计算(x1, y1)到(x2, y2)矩形区域的总和 total_sum = prefix_sum[x2][y2] if x1 > 0: total_sum -= prefix_sum[x1-1][y2] if y1 > 0: total_sum -= prefix_sum[x2][y1-1] if x1 > 0 and y1 > 0: total_sum += prefix_sum[x1-1][y1-1] return total_sum
这个代码中,compute_prefix_sum
函数用来计算原始矩阵的前缀和矩阵,query_sum
函数用来计算任意矩形区域的总和。调用compute_prefix_sum
函数可以获得前缀和矩阵,然后调用query_sum
函数可以查询任意矩形区域的总和。
五、差分
差分算法是一种用于计算离散数据序列的变化率或增量的算法。它可以用于多种领域,例如图像处理、时间序列分析、机器学习等。其核心思想是将序列中相邻的数据点之间的差值计算出来,从而得到一个新的序列,这个序列可以提供原序列中每个数据点的增量信息。
在差分算法中,有两种不同的方法:前向差分和后向差分。前向差分是将每个数据点与其后继数据点进行比较,而后向差分则是将每个数据点与其前驱数据点进行比较。这两种方法的实现非常相似,只需要将比较的方向更改即可。
以下是一个实现前向差分算法的Python代码:
def forward_difference(sequence): """ 计算序列的前向差分 参数: sequence: list,包含要计算的数据点的序列 返回值: list,包含序列的前向差分 """ diff = [] for i in range(len(sequence)-1): diff.append(sequence[i+1] - sequence[i]) return diff
该函数接受一个包含要计算的数据点的序列,并返回一个包含序列的前向差分的新序列。它遍历序列中的每个数据点,并将该数据点与其后继数据点进行比较,然后将它们之间的差值添加到一个新的序列中。最后,函数返回该新序列。
下面是一个实现后向差分算法的Python代码:
def backward_difference(sequence): """ 计算序列的后向差分 参数: sequence: list,包含要计算的数据点的序列 返回值: list,包含序列的后向差分 """ diff = [] for i in range(1, len(sequence)): diff.append(sequence[i] - sequence[i+1]) return diff
该函数接受一个包含要计算的数据点的序列,并返回一个包含序列的后向差分的新序列。它遍历序列中的每个数据点,并将该数据点与其前驱数据点进行比较,然后将它们之间的差值添加到一个新的序列中。最后,函数返回该新序列。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/134428.html