找到numpy数组中最大的方块

时间:2017-06-08 05:04:17

标签: python algorithm

我试图解决这个算法问题:在numpy数组中找到只有一个值的最大正方形。

示例图片:

example image

我的代码耗费了太多时间。有没有办法提高速度?

import numpy as np
answer = 0
def allsame(board):
    memory = board[0,0]
    board = np.matrix(board)
    for i in range(board[0].size):
        for j in range(board[0].size):
            if board[i,j] != memory: return False
    return True

def findLargestSquare(board):
    global answer
    list = []

    a = np.matrix(board)
    if a[0].size == 1 or a[:,1].size==1: return answer
    if a[1].size < a[:,1].size: ran = a[1].size
    else: ran = a[:,1].size
    for i in range(ran+1):
        for j in range(ran+1):
           if a[i:j,i:j].size > 0 and allsame(a[i:j,i:j])==True:
                    if a[i:j,i:j].size > answer:
                       list.append(a[i:j,i:j].size)
                       answer = a[i:j,i:j].size

    findLargestSquare(a[1:])
    return findLargestSquare(a[:,1:])
    return answer


#testBoard = [['x','o','g'],['b','a','j'],['u','q','p']]
testBoard = [['X','O','O','O','X'],['X','O','O','O','O'],['X','X','O','O','O'],['X','X','O','O','O'],['X','X','X','X','X']]
print(findLargestSquare(testBoard))

我将我的代码更改为自卷积方法。 你能看看哪一部分是错的吗?

import numpy as np
import time
answer = 0


def findLargestSquare(board):
    global answer


    a = np.array(board)

    for k in reversed(range(a[0].size + 1)):
        conv_size = k
        for i in range(a[0].size - conv_size + 1):
            num = i
            for j in range(a[0].size - conv_size + 1):
                #print('i:', i, 'j:', j)
                print(a[i:i + conv_size, j:j + conv_size])
                #print('unique: ',np.unique(a[i:i+ conv_size,j:j+conv_size]).size)
                if(np.unique(a[i:i+ conv_size,j:j+conv_size]).size == 1):
                    #print("returning")
                    return len(a[i:i+ conv_size,j:j+conv_size])**2
                num = num + 1
                print("================")
    return len(a[i:i+ conv_size,j:j+conv_size])**2



# testBoard = [['x','o','g'],['b','a','j'],['u','q','p']]
testBoard = [['X', 'O', 'O', 'O', 'X'], ['X', 'O', 'O', 'O', 'O'], ['X', 'X', 'O', 'O', 'O'], ['X', 'X', 'O', 'O', 'O'],
             ['X', 'X', 'X', 'X', 'X']]


print(findLargestSquare(testBoard))

5 个答案:

答案 0 :(得分:1)

您可以在O(n^2)而不是当前O(n^4)allsame()位于O(n^2)中,并且被称为O(n^2)次)来执行此操作:

使用新的矩阵best_size,这样best_size[i, j]应该包含原始棋盘中(i, j)开始的最大正方形的大小。从此规则结尾处开始填写此矩阵:

def get_best_size(a, best_size, i, j):
    # TODO Handle boundaries: best_size = 1 there
    if not a[i, j] == a[i+1, j] == a[i, j+1]:
        return 1
    min_neighbor_best_size = min(best_size[i+1, j], best_size[i, j+1])
    if a[i, j] == a[i + min_neighbor_best_size , j + min_neighbor_best_size ]:
        return min_neighbor_best_size + 1
    else:
        return min_neighbor_best_size 

只需绘制它就可以告诉您此规则的工作原理。

然后你只需从数组的末尾迭代到开始,并在你处于最佳位置时记住最好的一个:

best = 0
for i in range(ran,-1,-1):
    for j in range(ran,-1,-1):
        best_size[i, j] =  get_best_size(a, best_size, i, j)
        best = max(best, best_size[i, j])
return best

答案 1 :(得分:0)

您的代码存在一些根本性的问题,因为它不是您应该如何使用Python。首先尝试阅读一些好的介绍和示例。我推荐这个book和这些scipy lecture notes

让我们从顶部开始

allsame

有多种方法可以检查数组是否具有所有相同的元素

np.unique

numpy有一个返回unique元素的方法。如果所有元素都相同,则此数组的长度应为1

np.ones

您可以使用第一个元素,使用np.ones创建一个数组并将其与此元素相乘。初始数组应该等于这个新数组

findLargestSquare(板)

这种方法究竟应该做什么?

global answer

为什么要全球化?

``findLargestSquare(A [1:])`

此行被调用,但您对返回值不执行任何操作。它可能做的只是改变全局答案

列表

这个list会发生什么。 PS,不要给变量命名built-ins

矩阵

为什么要使用a = np.matrix(board)只需将您的电路板保持为​​numpy.array,这将是最简单,最有效的。另外,01的矩阵将比X0

更有效率

.size

如果要在两个方向之一的大小为1时停止算法的递归,1 in a.shape

替代方法

如果你想在0&n;的numpy.array中找到1上的方块,你可以使用卷积

数组创建

a = np.zeros((10,10), dtype=int)
ones = ((1, 1), (1, 2), (2, 1), (2, 2), (0, 0), (4, 5))
for point in ones:
    a[point] = 1

内核创建和卷积

这使用卷积来搜索原始数组中是否有i i内核

def find_largest_square_helper(a):
    for i in range(2, min(a.shape)): # changed this to 2, because the 1 is trivial
        kernel = np.ones((i, i), dtype=int)
        if scipy.signal.convolve(a, kernel).max() != i**2:
            return(i-1)

如果你期望大方块,你可以从最大的方块开始,然后像这样下去:

def find_largest_square_helper2(a):
    for i in range(min(a.shape), 0, -1):
        kernel = np.ones((i, i), dtype=int)
        if scipy.signal.convolve(a, kernel).max() == i**2:
            return(i)

超过1个字符

如果您不仅在1数组中查找0 s的最大平方,则循环遍历数组中的所有可能字符,并在集合理解中调用此函数。然后在set

中查找最大值
def find_largest_square(board):
    a = np.array(board)
    max_squares = {find_largest_square_helper(a==char) for char in np.unique(a)}
    return max(max_squares)

答案 2 :(得分:0)

第二次尝试的改进

        <!--  **ImgDashboard.js** -->

         Template.ImgDashboard.helpers({
        setImageProcessing: function() {
                var roomId = localStorage.getItem('roomId');/*set localstorage */ 
                var imageData = ImageData.findOne({RoomId: roomId});
/* ImageData collection in Mongodb */ 
                setTimeout(function(){
                var item = "";
                imageData.ImageData.forEach(function(data){
                var base64String = data.ImageString;  

             item += '<div class="col-xs-12 col-sm-6 col-md-3 col-lg-3" >\
                         <div class="center-block"  width="300" height="300" 
                alt="" >\
                <img src='+base64String+' class= "img-responsive center-
                 block"/>\
                 </div>\</div>'; /* concatenation of images */ 

                  }, function(err){

                 }) 
                $('.image-list').append(item); 

                 },10)   


              });


         <!-- **ImgDashboard.html** -->

            <template name="ImgDashboard">  /* template rendered here to display */
             {{> Header}}
            <div class="container-fluid">
            <div> {{setImageProcessing}}</div> /* method from helper */ 
            <div class="image-list">/* images here from helper */ 

            </div>
            </div>
            </template>


      <!--  **Room.html** -->


            <div class="container-fluid">
            <div class="row">

          <div id="carousel-example-generic" class="carousel slide" data-
      ride="carousel">
            <div class="carousel-inner" role="listbox">
              <div class="item active">
                <img src="images/bedroom-lg.jpeg" class="img-responsive" width="100%" height="597">  /* First block */ 
              </div>
              <div class="item">
                <img src="images/bedroom-lg.jpeg" class="img-responsive" width="100%" height="597"> /* second block */ 
              </div>
              <div class="item">
                <img src="images/bedroom-lg.jpeg" class="img-responsive" width="100%" height="597"> /* third block */ 
              </div>
              <div class="item">
                <img src="images/bedroom-lg.jpeg" class="img-responsive" width="100%" height="597">/* fourth block */ 
              </div>
              <div class="item">
                <img src="images/bedroom-lg.jpeg" class="img-responsive" width="100%" height="597">/* fifth block */ 
              </div>
            </div>

            /* -- Controls -- */
            <a class="left carousel-control" href="#carousel-example-generic" role="button" data-slide="prev">
              <span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
              <span class="sr-only">Previous</span>
            </a>  
            <a class="right carousel-control" href="#carousel-example-generic" role="button" data-slide="next">
              <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
              <span class="sr-only">Next</span>
            </a> 
          </div>

            </div>
        </div>

import numpy as np import time answer = 0 def findLargestSquare(board): global answer a = np.array(board) for k in reversed(range(a[0].size + 1)): conv_size = k for i in range(a[0].size - conv_size + 1): num = i for j in range(a[0].size - conv_size + 1): #print('i:', i, 'j:', j) print(a[i:i + conv_size, j:j + conv_size]) #print('unique: ',np.unique(a[i:i+ conv_size,j:j+conv_size]).size) if(np.unique(a[i:i+ conv_size,j:j+conv_size]).size == 1): #print("returning") return len(a[i:i+ conv_size,j:j+conv_size])**2 num = num + 1 print("================") return len(a[i:i+ conv_size,j:j+conv_size])**2

是不必要的,无处可用。当然不需要在算法中使用answer

重命名变量

globalconv_size = k是不必要的。如果你想这样命名,那么在for循环中这样做,num = i甚至不用于算法的其余部分

num

每次创建一个新数组(或range(a[0].size),我不是100%肯定),如果view更短,则会产生问题。 a[1]更清洁

双重for-loop

代替循环两次,您可以使用max_size = min(a.shape)生成子方格边缘的坐标

itertools.product

返回一个生成器,其结果为5:

  

[(0,0),(0,1),(0,2),(0,3),(0,4),(1,0),(1,1),(1,2) ),(1,3),(1,4),(2,0),(2,1),(2,2),(2,3),(2,4),(3,0), (3,1),(3,2),(3,3),(3,4),(4,0),(4,1),(4,2),(4,3),(4) ,4)]

检查本身

for size in reversed(range(2,  max_size + 1)):
    k = max_size = size + 1
    for i, j in itertools.product(range(k), repeat=2):
如果没有if(np.unique(a[i:i+ conv_size,j:j+conv_size]).size == 1): #print("returning") return len(a[i:i+ conv_size,j:j+conv_size])**2 array

的双重创建,

可以更干净

view

联合

sub_square = a[i:i+size, j:j+size]
if len(np.unique(sub_square)) == 1:
    return len(sub_square) ** 2
        # calculations

答案 3 :(得分:0)

我确定了第一个答案:

def get_best_size(a, best_size, i, j, x):
    if i+1 >= a.shape[0] or j+1 >= a.shape[1]:
        return 1
    if not (a[i, j] == a[i+1, j] == a[i, j+1] == x):
        return 1
    min_neighbor_best_size = int(min(best_size[i+1, j], best_size[i, j+1]))
    if a[i, j] == a[i + min_neighbor_best_size , j + min_neighbor_best_size ]:
        return min_neighbor_best_size + 1
    else:
        return min_neighbor_best_size

# looking for largest X block in A
def doGetBest(a, x):
    best_size = np.ones(a.shape)
    best = 1
    best_pair = (0,0)
    for i in range(a.shape[0]-1,-1,-1):
        for j in range(a.shape[1]-1,-1,-1):
            best_size[i, j] =  get_best_size(a, best_size, i, j, x)
            if best < best_size[i, j]:
                best = best_size[i, j]
                best_pair = (i,j)

    return best, best_pair

答案 4 :(得分:0)

由于没有人提供DP方法示例,因此它是:

def findLargestSquare(M): 
    n = len(M) 
    S = [[0 for _ in range(n)] for _ in range(n)] 
    max_s = 0
    for i in range(1, n): 
        for j in range(1, n): 
            if M[i][j] == 1: 
                S[i][j] = min(S[i][j-1], S[i-1][j], S[i-1][j-1]) + 1
                if S[i][j] > max_s:
                    max_s = S[i][j]
    return max_s

作为比较,这是我在求职面试中想到的一种蛮力方法(对于500x500矩阵,它要慢100倍):

def findLargestSquare(arr):
    if sum([sum(row) for row in arr]) == 0:  
        return 0
    n = len(arr)
    for k in range(n, 1, -1):  #check every kxk square from k=n to k=2
        for i in range(n-k+1):
            #for every row i check every starting position j from j=0 to j=n-k
            j_next = 0
            for j in range(n-k+1):
                if j > j_next:
                    #break as soon as an element of this row segment is not 1:
                    count = 0
                    for p in range(j, j+k, 1):
                        if arr[i][p] != 1:
                            j_next = p
                            break
                    else:  ##check the rows below:
                        keep_going = True
                        for r in range(i+1, i+k, 1):
                            if keep_going:
                                for p in range(j, j+k, 1):
                                    if arr[r][p] != 1:
                                        keep_going = False
                                        j_next = p
                                        break
                                else:
                                    count += 1
                                if count == k-1: #square is found
                                    return k
    else:
        return 1