python分治法求二维数组局部峰值方法


Posted in Python onApril 03, 2018

题目的意思大致是在一个n*m的二维数组中,找到一个局部峰值。峰值要求大于相邻的四个元素(数组边界以外视为负无穷),比如最后我们找到峰值A[j][i],则有A[j][i] > A[j+1][i] && A[j][i] > A[j-1][i] && A[j][i] > A[j][i+1] && A[j][i] > A[j][i-1]。返回该峰值的坐标和值。

当然,最简单直接的方法就是遍历所有数组元素,判断是否为峰值,时间复杂度为O(n^2)

再优化一点求每一行(列)的最大值,再通过二分法找最大值列的峰值(具体方法可见一维数组求峰值),这种算法时间复杂度为O(logn)

这里讨论的是一种复杂度为O(n)的算法,算法思路分为以下几步:

1、找“田”字。包括外围的四条边和中间横竖两条边(图中绿色部分),比较其大小,找到最大值的位置。(图中的7)

python分治法求二维数组局部峰值方法

2、找到田字中最大值后,判断它是不是局部峰值,如果是返回该坐标,如果不是,记录找到相邻四个点中最大值坐标。通过该坐标所在的象限缩小范围,继续比较下一个田字

python分治法求二维数组局部峰值方法

3、当范围缩小到3*3时必定会找到局部峰值(也可能之前就找到了)

关于为什么我们选择的范围内一定存在峰值,大家可以这样想,首先我们有一个圈,我们已知有圈内至少有一个元素大于这个圈所有的元素,那么,是不是这个圈中一定有一个最大值?

可能说得有点绕,但是多想想应该能够理解,也可以用数学的反证法来证明。

算法我们理解后接下来就是代码实现了,这里我用的语言是python(初学python,可能有些用法上不够简洁请见谅),先上代码:

import numpy as np
def max_sit(*n):     #返回最大元素的位置
 temp = 0
 sit = 0
 for i in range(len(n)):
  if(n[i]>temp):
   temp = n[i]
   sit = i
 return sit
def dp(s1,s2,e1,e2):
 m1 = int((e1-s1)/2)+s1   #row
 m2 = int((e2-s1)/2)+s2   #col
 nub = e1-s1
 temp = 0
 sit_row = 0
 sit_col = 0
 for i in range(nub):
  t = max_sit(list[s1][s2+i],     #第一排
     list[m1][s2+i],     #中间排
     list[e1][s2+i],     #最后排
     list[s1+i][s2],     #第一列
     list[s1+i][m2],     #中间列
     list[s1+i][e2],     #最后列
     temp)
  if(t==6):
   pass
  elif(t==0):
   temp = list[s1][s2+i]
   sit_row = s1
   sit_col = s2+i
  elif(t==1):
   temp = list[m1][s2+i]
   sit_row = m1
   sit_col = s2+i
  elif(t==2):
   temp = list[e1][s2+i]
   sit_row = e1
   sit_col = s2+i
  elif(t==3):
   temp = list[s1+i][s2]
   sit_row = s1+i
   sit_row = s2
  elif(t==4):
   temp = list[s1+i][m2]
   sit_row = s1+i
   sit_col = m2
  elif(t==5):
   temp = list[s1+i][e2]
   sit_row = s1+i
   sit_col = m2
 t = max_sit(list[sit_row][sit_col],   #中
    list[sit_row-1][sit_col],  #上
    list[sit_row+1][sit_col],  #下
    list[sit_row][sit_col-1],  #左
    list[sit_row][sit_col+1])  #右
 if(t==0):
  return [sit_row-1,sit_col-1]
 elif(t==1):
  sit_row-=1
 elif(t==2):
  sit_row+=1
 elif(t==3):
  sit_col-=1
 elif(t==4):
  sit_col+=1
 if(sit_row<m1):
  e1 = m1
 else:
  s1 = m1
 if(sit_col<m2):
  e2 = m2
 else:
  s2 = m2
 return dp(s1,s2,e1,e2)
f = open("demo.txt","r")
list = f.read()
list = list.split("\n")       #对行进行切片
list = ["0 "*len(list)]+list+["0 "*len(list)] #加上下的围墙
for i in range(len(list)):      #对列进行切片
 list[i] = list[i].split()
 list[i] = ["0"]+list[i]+["0"]    #加左右的围墙
list = np.array(list).astype(np.int32)
row_n = len(list)
col_n = len(list[0])
ans_sit = dp(0,0,row_n-1,col_n-1)
print("找到峰值点位于:",ans_sit)
print("该峰值点大小为:",list[ans_sit[0]+1,ans_sit[1]+1])
f.close()

首先我的输入写在txt文本文件里,通过字符串转换变为二维数组,具体转换过程可以看我上一篇博客——python中字符串转换为二维数组。(需要注意的是如果在windows环境中split后的列表没有空尾巴,所以不用加list.pop()这句话)。有的变动是我在二维数组四周加了“0”的围墙。加围墙可以再我们判断峰值的时候不用考虑边界问题。

max_sit(*n)函数用于找到多个值中最大值的位置,返回其位置,python的内构的max函数只能返回最大值,所以还是需要自己写,*n表示不定长参数,因为我需要在比较田和十(判断峰值)都用到这个函数

def max_sit(*n):     #返回最大元素的位置
 temp = 0
 sit = 0
 for i in range(len(n)):
  if(n[i]>temp):
   temp = n[i]
   sit = i
 return sit

dp(s1,s2,e1,e2)函数中四个参数的分别可看为startx,starty,endx,endy。即我们查找范围左上角和右下角的坐标值。

m1,m2分别是row 和col的中间值,也就是田字的中间。

def dp(s1,s2,e1,e2): 
 m1 = int((e1-s1)/2)+s1   #row 
 m2 = int((e2-s1)/2)+s2   #col

依次比较3行3列中的值找到最大值,注意这里要求二维数组为正方形,如果为矩形需要做调整

for i in range(nub):
  t = max_sit(list[s1][s2+i],     #第一排
     list[m1][s2+i],     #中间排
     list[e1][s2+i],     #最后排
     list[s1+i][s2],     #第一列
     list[s1+i][m2],     #中间列
     list[s1+i][e2],     #最后列
     temp)
  if(t==6):
   pass
  elif(t==0):
   temp = list[s1][s2+i]
   sit_row = s1
   sit_col = s2+i
  elif(t==1):
   temp = list[m1][s2+i]
   sit_row = m1
   sit_col = s2+i
  elif(t==2):
   temp = list[e1][s2+i]
   sit_row = e1
   sit_col = s2+i
  elif(t==3):
   temp = list[s1+i][s2]
   sit_row = s1+i
   sit_row = s2
  elif(t==4):
   temp = list[s1+i][m2]
   sit_row = s1+i
   sit_row = m2
  elif(t==5):
   temp = list[s1+i][e2]
   sit_row = s1+i
   sit_row = m2

判断田字中最大值是不是峰值,并找不出相邻最大值

t = max_sit(list[sit_row][sit_col],   #中 
    list[sit_row-1][sit_col],  #上 
    list[sit_row+1][sit_col],  #下 
    list[sit_row][sit_col-1],  #左 
    list[sit_row][sit_col+1])  #右 
 if(t==0): 
  return [sit_row-1,sit_col-1] 
 elif(t==1): 
  sit_row-=1 
 elif(t==2): 
  sit_row+=1 
 elif(t==3): 
  sit_col-=1 
 elif(t==4): 
  sit_col+=1

缩小范围,递归求解

if(sit_row<m1): 
  e1 = m1 
 else: 
  s1 = m1 
 if(sit_col<m2): 
  e2 = m2 
 else: 
  s2 = m2 
 
 return dp(s1,s2,e1,e2)

好了,到这里代码基本分析完了。如果还有不清楚的地方欢迎下方留言。

除了这种算法外,我也写一种贪心算法来求解这道题,只可惜最坏的情况下算法复杂度还是O(n^2),QAQ。

大体的思路就是从中间位置起找相邻4个点中最大的点,继续把该点来找相邻最大点,最后一定会找到一个峰值点,有兴趣的可以看一下,上代码:

#!/usr/bin/python3
def dp(n):
 temp = (str[n],str[n-9],str[n-1],str[n+1],str[n+9])  #中 上 左 右 下
 sit = temp.index(max(temp))
 if(sit==0):
  return str[n]
 elif(sit==1):
  return dp(n-9)
 elif(sit==2):
  return dp(n-1)
 elif(sit==3):
  return dp(n+1)
 else:
  return dp(n+9)
f = open("/home/nancy/桌面/demo.txt","r")
list = f.read()
list = list.replace(" ","").split()  #转换为列表
row = len(list)
col = len(list[0])
str="0"*(col+3)
for x in list:      #加围墙 二维变一维
 str+=x+"00"
str+="0"*(col+1)
mid = int(len(str)/2)
print(str,mid)
p = dp(mid)
print (p)
f.close()

以上这篇python分治法求二维数组局部峰值方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python实现堆栈与队列的方法
Jan 15 Python
Python基础教程之tcp socket编程详解及简单实例
Feb 23 Python
python机器学习理论与实战(四)逻辑回归
Jan 19 Python
利用Python写一个爬妹子的爬虫
Jun 08 Python
PyCharm代码整体缩进,反向缩进的方法
Jun 25 Python
python中实现字符串翻转的方法
Jul 11 Python
用Pycharm实现鼠标滚轮控制字体大小的方法
Jan 15 Python
Python抓新型冠状病毒肺炎疫情数据并绘制全国疫情分布的代码实例
Feb 05 Python
使用python 计算百分位数实现数据分箱代码
Mar 03 Python
浅谈python多线程和多线程变量共享问题介绍
Apr 17 Python
TensorFlow Autodiff自动微分详解
Jul 06 Python
python,Java,JavaScript实现indexOf
Sep 09 Python
Python变量赋值的秘密分享
Apr 03 #Python
python中字符串变二维数组的实例讲解
Apr 03 #Python
numpy找出array中的最大值,最小值实例
Apr 03 #Python
Python获取二维矩阵每列最大值的方法
Apr 03 #Python
Python中的并发处理之asyncio包使用的详解
Apr 03 #Python
图解Python变量与赋值
Apr 03 #Python
Python实现的HMacMD5加密算法示例
Apr 03 #Python
You might like
php 用sock技术发送邮件的函数
2007/07/21 PHP
使用PHP的日期与时间函数技巧
2008/04/24 PHP
Yii操作数据库的3种方法
2014/03/11 PHP
php实现网页缓存的工具类分享
2015/07/14 PHP
老生常谈PHP 文件写入和读取(必看篇)
2017/05/22 PHP
PHP全局使用Laravel辅助函数dd
2019/12/26 PHP
基于jquery的复制网页内容到WORD的实现代码
2011/02/16 Javascript
使用javascript实现json数据以csv格式下载
2015/01/09 Javascript
JQuery包裹DOM节点的方法
2015/06/11 Javascript
在JavaScript中使用对数Math.log()方法的教程
2015/06/15 Javascript
js性能优化技巧
2015/11/29 Javascript
js判断登陆用户名及密码是否为空的简单实例
2016/05/16 Javascript
简单实现jQuery多选框功能
2017/01/09 Javascript
Angular中ng-repeat与ul li的多层嵌套重复问题
2017/07/24 Javascript
vue中的计算属性实例详解
2018/09/19 Javascript
4个顶级JavaScript高级文本编辑器
2018/10/10 Javascript
webpack 静态资源集中输出的方法示例
2018/11/09 Javascript
Next.js项目实战踩坑指南(笔记)
2018/11/29 Javascript
es6函数之严格模式用法实例分析
2020/03/17 Javascript
python计算最大优先级队列实例
2013/12/18 Python
python中使用序列的方法
2015/08/03 Python
python中异常报错处理方法汇总
2016/11/20 Python
python处理xml文件的方法小结
2017/05/02 Python
python中的插值 scipy-interp的实现代码
2018/07/23 Python
Django实现跨域请求过程详解
2019/07/25 Python
利物浦足球俱乐部官方商店(美国):Liverpool FC US
2019/10/09 全球购物
Java中有几种类型的流?JDK为每种类型的流提供了一些抽象类以供继承,请说出他们分别是哪些类
2012/02/06 面试题
通信工程专业女生个人求职信
2013/09/21 职场文书
应届医学毕业生求职信分享
2013/12/02 职场文书
预备党员转正思想汇报
2014/01/12 职场文书
十八届三中全会报告学习材料
2014/02/17 职场文书
中学生演讲稿
2014/04/26 职场文书
医生个人自我剖析材料
2014/10/08 职场文书
2014年药店工作总结
2014/11/20 职场文书
金秋助学感谢信
2015/01/21 职场文书
56句经典英文座右铭
2019/08/09 职场文书