博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
MIT - Peak Finding
阅读量:5041 次
发布时间:2019-06-12

本文共 2675 字,大约阅读时间需要 8 分钟。

MIT一直是免费公开课的传播者和引领者,旨在为全世界各地的人们提供免费可在线观看的大学课程。将精英大学的课程搬到网上,会造福整个人类。

这一分类博文将跟随MIT的6006课程《Introduction to Algorithms》,实现课程中所讲到的算法。
首先讲到的是算法思想,如何通过将复杂问题,高纬度问题简单化。一种好的思路是通过将大的问题,复杂的问题划分成子问题,通过子问题的解决,从而解决复杂问题。最经典的思想就是“DIvide &
Conquer”以及“Recursive”,分而治之和递归的思想。

问题一

Peak Finding:在任何一个一维数组中,均存在至少一个peak,当然,数组长度大于0。若a[k] >= a[k - 1]且a[k] >= a[k + 1](k > 0且k < n - 2),则说a[k]为peak。a[0]为peak若a[0] >= a[1], a[n - 1]为peak若a[n - 1] >= a[n - 2]。

有了定义之后如何在一个数组中找到一个peak呢?如果我们从第一个元素开始遍历整个数组,当然可以找到一个peak。每当遍历到一个元素的时候,我们同时比较其左右邻居,若都比其邻居大或相等,则为peak。我们知道,遍历整个数组的时间复杂度为\(O(n)\)。既然学习的是算法导论,就会选择更高效的算法实现。
采用分而治之的思想,我们可以使用二分查找法,如下图:
1410597-20181107223346074-821195333.png
我们先找中间的元素,若恰好找到,则返回。若中间的元素比其左邻居小,那么我们只从0到2/n - 1的范围查找peak。若中间的元素的元素比其又邻居小,那么我们只从2/n + 1到n - 1的范围查找。

代码实现

def find_1d_peak(arr):    return find_1d_peak_util(arr, 0, len(arr) - 1)def find_1d_peak_util(arr, low, high):    mid = (low + high) // 2    if mid > 0 and arr[mid] < arr[mid - 1]:        return find_1d_peak_util(arr, low, mid - 1)    elif mid < len(arr) - 1 and arr[mid] < arr[mid + 1]:        return find_1d_peak_util(arr, mid + 1, high)    return midtest_1d = [1, 2, 3, 1]print(find_1d_peak(test_1d))

逻辑很简单,采用折半查找和递归的方式,这样整个的时间复杂度可以降为\(O(\log_2n)\)

问题二

依然是Peak Finding,这次我们要在二维数组(矩阵)中查找一个peak。定义:若a[i][i]同时>=(a[i - 1][j], a[i + 1][j], a[i][j - 1], a[i][j + 1]),既同时大于其上下左右四个邻居,则其为一个peak,边界元素若缺少某些邻居,也依然为peak。

思路:问题一为一维,采用的是二分查找和递归的思想。问题二依然可以用此思想,只不过是增加了一个纬度而已。我们依然是二分,只不过这次是按列二分。首先在中间列里找到一个最大值。既j = m / 2,找到第j列中的最大值为martix[i][j]。比较martix[i][j]其左右邻居martix[i][j - 1]和martix[i][j + 1]。若同时大于等于其左右邻居,则为peak(在该列中最大,则也同时大于等于其上下邻居)。若martix[i][j]<=martix[i][j - 1],则在列为0到j - 1的位置查找,继续二分。若martix[i][j]<=martix[i][j + 1],则在列为j + 1到m - 1的位置查找,继续二分。

代码实现

def find_2d_peak(martix):    return find_2d_peak_util(martix, 0, len(martix[0]) - 1)def find_2d_peak_util(martix, low, high):    mid = (low + high) // 2    max_row = 0    max_value_in_row = martix[max_row][mid]    for i in range(1, len(martix)):        if martix[i][mid] > max_value_in_row:            max_value_in_row = martix[i][mid]            max_row = i    if mid > 0 and max_value_in_row < martix[max_row][mid - 1]:        return find_2d_peak_util(martix, low, mid - 1)    elif mid < len(martix[0]) - 1 and max_value_in_row < martix[max_row][mid + 1]:        return find_2d_peak_util(martix, mid + 1, high)    return [max_row, mid]test_2d = [[10,8,10, 10], [14, 13, 12, 11], [15, 9, 11, 21], [16, 17, 19, 20]]print(find_2d_peak(test_2d))

思路和问题一完全一致,只不过增加了一个维度而已。若n行m列的矩阵,则其时间复杂度为\(O(n\log_2m)\)。若m = n,则为\(O(nlog_2n)\)。注意每一列查找最大值的时间复杂度为\(O(n)\)

总结

该问题是比较典型的二分查找和递归算法,通过将大的问题划分为子问题,通过求解子问题来实现复杂问题的解决。值得注意的是在二个问题中都要注意边界的控制,否则容易出现“index out of range”的常见错误。

转载于:https://www.cnblogs.com/jeffrey-yang/p/9926297.html

你可能感兴趣的文章
System.ValueTuple 未定義或匯入預先定義的類型
查看>>
Redhat6.4安装Oracle 11gr2 64位 注意事项
查看>>
rpm
查看>>
Finance_books_LTCM
查看>>
Http协议
查看>>
2016福州大学软件工程第二次团队作业——预则立&&他山之石成绩统计
查看>>
HDU - 5338 ZZX and Permutations 线段树 + set
查看>>
Windbg分析蓝屏Dump文件
查看>>
问题集锦
查看>>
设置tomcat内存设定
查看>>
Django:中间件与csrf
查看>>
Access specifier 访问限定词
查看>>
js怎么获取动态链式属性呢?
查看>>
【python进阶】Garbage collection垃圾回收1
查看>>
调度系统任务创建---创建一个JoinTrigger的依赖任务(五)
查看>>
Leetcode-Read N Characters Given Read4
查看>>
九年程序人生 总结分享
查看>>
Balanced Lineup
查看>>
C语言:数据类型
查看>>
C# string和byte[]数组之间相互转换
查看>>