List 利用haskell的最大正子矩阵

List 利用haskell的最大正子矩阵,list,haskell,matrix,functional-programming,submatrix,List,Haskell,Matrix,Functional Programming,Submatrix,我有以下问题: 给你矩阵m*n,你必须找到从(1,1)到(x,y)的最大正(子矩阵的所有元素都应该大于0)子矩阵 我所说的最大值是指,当你有以下矩阵时: [[1,2,3,4],[5,6,7,8],[9,10,-11,12],[13,14,15,16]] 最大正子矩阵为: [[[1,2,3,4],[5,6,7,8]],[[1,2],[5,6],[9,10],[13,14]]] i、 e.前两行是一个解决方案,前两列是第二个解决方案 另一个例子:矩阵是 [[1,2,3,-4],[5,6,7,8

我有以下问题:

给你矩阵m*n,你必须找到从(1,1)到(x,y)的最大正(子矩阵的所有元素都应该大于0)子矩阵

我所说的最大值是指,当你有以下矩阵时:

 [[1,2,3,4],[5,6,7,8],[9,10,-11,12],[13,14,15,16]]
最大正子矩阵为:

[[[1,2,3,4],[5,6,7,8]],[[1,2],[5,6],[9,10],[13,14]]]
i、 e.前两行是一个解决方案,前两列是第二个解决方案

另一个例子:矩阵是

[[1,2,3,-4],[5,6,7,8],[-9,10,-11,12],[13,14,15,16]]
解决办法是:

[[[1,2,3],[5,6,7]]]
这是我的Haskell程序,它解决了这个问题:

import Data.List hiding (insert)

import qualified Data.Set as Set

unique :: Ord a => [a] -> [a]
unique = Set.toList . Set.fromList


subList::[[Int]] ->[[[Int]]]
subList matrix = filter (allPositiveMatrix) $  [ (submatrix matrix 1 1 x y) |   x<-[1..width(matrix)], y<-[1..height(matrix)]]


maxWidthMat::[[[Int]]] -> Int
maxWidthMat subList =length ((foldl (\largestPreviousX nextMatrix -> if (length (nextMatrix!!0)) >(length (largestPreviousX !!0)) then nextMatrix  else largestPreviousX ) [[]] subList)!!0)


maxWidthSubmatrices:: [[[Int]]] -> Int ->[[[Int]]]
maxWidthSubmatrices subList maxWidth = filter (\x -> (length $x!!0)==maxWidth) subList

height matrix = length matrix

width matrix = length (matrix!!0)

maximalPositiveSubmatrices matrix =  maxWidthSubmatrices (subList matrix) (maxWidthMat   (filter (\x -> (length $x!!0)==( maxWidthMat $ subList matrix )) (subList matrix)))


allPositiveList list = foldl (\x y -> if (y>0)&&(x==True) then True else False) True list

allPositiveMatrix:: [[Int]] -> Bool
allPositiveMatrix matrix = foldl (\ x y -> if (allPositiveList y)&&(x==True) then True else False  )  True matrix


submatrix matrix x1 y1 x2 y2 = slice ( map (\x -> slice x x1 x2) matrix) y1 y2

slice list x y = drop (x-1)  (take y list)



maximalWidthSubmatrix mm =  maximum $ maximalPositiveSubmatrices mm
maximalHeigthSubmatrix mm = transpose $ maximum $ maximalPositiveSubmatrices $ transpose mm

-- solution
solution matrix =unique $ [maximalWidthSubmatrix matrix]++[maximalHeigthSubmatrix matrix]
导入数据。列表隐藏(插入)
导入符合条件的数据。设置为集合
唯一::Ord a=>[a]->[a]
unique=Set.toList。Set.fromList
子列表::[[Int]]->[[[Int]]]
子列表矩阵=过滤器(所有正矩阵)$[(子矩阵1 x y)| x如果(长度(nextMatrix!!0))>(长度(largestPreviousX!!0)),则nextMatrix else largestPreviousX)[[]]子列表!!0)
maxWidthSubmatrices::[[[Int]]]->Int->[[[Int]]]
maxWidthSubmatrices子列表maxWidth=filter(\x->(长度$x!!0)=maxWidth)子列表
高度矩阵=长度矩阵
宽度矩阵=长度(矩阵!!0)
maximalPositiveSubmatrices矩阵=maxWidthSubmatrices(子列表矩阵)(maxWidthMat(过滤器(\x->(长度$x!!0)=(maxWidthMat$子列表矩阵))(子列表矩阵)))
allPositiveList=foldl(\x y->if(y>0)和&(x==True)则为True,否则为False)True list
allPositiveMatrix::[[Int]]->Bool
allPositiveMatrix=foldl(\x y->if(allPositiveList y)&&(x==True)则为True,否则为False)真矩阵
子矩阵x1 y1 x2 y2=切片(映射(\x->切片x x1 x2)矩阵)y1 y2
切片列表XY=放置(x-1)(取y列表)
maximalWidthSubmatrix mm=最大$maximalPositiveSubmatrices mm
MaximalHeightsSubmatrix mm=转置$Maximal$maximalPositiveSubmatrices$转置mm
--解决方案
解矩阵=唯一$[maximalWidthSubmatrix]+[maximalHeigthSubmatrix]
正如你所看到的,它极其冗长和丑陋。 它可能也不是最快的

你能给我展示更优雅、更快和更短的解决方案(可能有解释)吗 我认为为了解决这个问题,我们首先最好进行降维:

reduce_dim :: (Num a,Ord a) => [[a]] -> [Int]
reduce_dim = map (length . takeWhile (>0))  -- O(m*n)
这里,对于每一行,我们计算从左边开始的正项数。因此对于给定的矩阵:

 1   2   3   4  | 4
 5   6   7   8  | 4
 9  10 -11  12  | 2
13  14  15  16  | 4
因此,第二行映射为2,因为第三个元素是-11

或者对于其他矩阵:

 1   2   3  -4  | 3
 5   6   7   8  | 4
-9  10 -11  12  | 0
13  14  15  16  | 4
因为第一行在第4列有-4,第三行在第1列有-4

现在我们可以在这些行上获得
scanl1 min

Prelude> scanl1 min [4,4,2,4] -- O(m)
[4,4,2,2]
Prelude> scanl1 min [3,4,0,4] -- O(m)
[3,3,0,0]
现在,每次数量减少(并且在最后),我们都知道我们在上面的行中找到了一个最大子矩阵。因为这意味着我们现在处理的是从何处开始的一行,列的数量更少。一旦我们达到零,我们知道进一步的计算没有意义,因为我们处理的是一个0列的矩阵

因此,基于该列表,我们可以简单地生成一个最大子矩阵大小的元组列表:

max_sub_dim :: [Int] -> [(Int,Int)]
max_sub_dim = msd 1  -- O(m)
    where msd r []             = []
          msd r (0:_)          = []
          msd r [c]            = [(r,c)]
          msd r (c1:cs@(c2:_)) | c2 < c1 = (r,c1) : msd (r+1) cs
                               | otherwise = msd (r+1) cs
现在我们只需要获得这些子矩阵本身。我们可以通过使用
take
map
over
take
来实现这一点:

construct_sub :: [[a]] -> [(Int,Int)] -> [[[a]]]
construct_sub mat = map (\(r,c) -> take r (map (take c) mat))  -- O(m^2*n)
现在我们只需要在一个
解算

-- complete program

reduce_dim :: (Num a,Ord a) => [[a]] -> [Int]
reduce_dim = map (length . takeWhile (>0))

max_sub_dim :: [Int] -> [(Int,Int)]
max_sub_dim = msd 1
    where msd r []             = []
          msd r (0:_)          = []
          msd r [c]            = [(r,c)]
          msd r (c1:cs@(c2:_)) | c2 < c1 = (r,c1) : msd (r+1) cs
                               | otherwise = msd (r+1) cs

construct_sub :: [[a]] -> [(Int,Int)] -> [[[a]]]
construct_sub mat = map (\(r,c) -> take r (map (take c) mat))

solve :: (Num a,Ord a) => [[a]] -> [[[a]]]
solve mat = construct_sub mat $ max_sub_dim $ scanl1 min $ reduce_dim mat
时间复杂性 该算法在O(m×n)中运行,m为行数,n为列数,以构造矩阵的维度

所有的子矩阵都需要O(m2×n)来构造,因此算法在O(m2×n)中运行

我们可以转换方法,在列而不是行上运行。因此,如果我们使用的是行数与列数相差很大的矩阵,我们可以首先计算最小值(可选地进行转换),从而使m成为两个矩阵中最小的一个

潜在优化点 我们可以通过在构造
max\u sub\u dim
的同时构造子矩阵来加快算法的速度。

提出的算法 我认为为了解决这个问题,我们首先最好进行降维:

reduce_dim :: (Num a,Ord a) => [[a]] -> [Int]
reduce_dim = map (length . takeWhile (>0))  -- O(m*n)
这里,对于每一行,我们计算从左边开始的正项数。因此对于给定的矩阵:

 1   2   3   4  | 4
 5   6   7   8  | 4
 9  10 -11  12  | 2
13  14  15  16  | 4
因此,第二行映射为2,因为第三个元素是-11

或者对于其他矩阵:

 1   2   3  -4  | 3
 5   6   7   8  | 4
-9  10 -11  12  | 0
13  14  15  16  | 4
因为第一行在第4列有-4,第三行在第1列有-4

现在我们可以在这些行上获得
scanl1 min

Prelude> scanl1 min [4,4,2,4] -- O(m)
[4,4,2,2]
Prelude> scanl1 min [3,4,0,4] -- O(m)
[3,3,0,0]
现在,每次数量减少(并且在最后),我们都知道我们在上面的行中找到了一个最大子矩阵。因为这意味着我们现在处理的是从何处开始的一行,列的数量更少。一旦我们达到零,我们知道进一步的计算没有意义,因为我们处理的是一个0列的矩阵

因此,基于该列表,我们可以简单地生成一个最大子矩阵大小的元组列表:

max_sub_dim :: [Int] -> [(Int,Int)]
max_sub_dim = msd 1  -- O(m)
    where msd r []             = []
          msd r (0:_)          = []
          msd r [c]            = [(r,c)]
          msd r (c1:cs@(c2:_)) | c2 < c1 = (r,c1) : msd (r+1) cs
                               | otherwise = msd (r+1) cs
现在我们只需要获得这些子矩阵本身。我们可以通过使用
take
map
over
take
来实现这一点:

construct_sub :: [[a]] -> [(Int,Int)] -> [[[a]]]
construct_sub mat = map (\(r,c) -> take r (map (take c) mat))  -- O(m^2*n)
现在我们只需要在一个
解算

-- complete program

reduce_dim :: (Num a,Ord a) => [[a]] -> [Int]
reduce_dim = map (length . takeWhile (>0))

max_sub_dim :: [Int] -> [(Int,Int)]
max_sub_dim = msd 1
    where msd r []             = []
          msd r (0:_)          = []
          msd r [c]            = [(r,c)]
          msd r (c1:cs@(c2:_)) | c2 < c1 = (r,c1) : msd (r+1) cs
                               | otherwise = msd (r+1) cs

construct_sub :: [[a]] -> [(Int,Int)] -> [[[a]]]
construct_sub mat = map (\(r,c) -> take r (map (take c) mat))

solve :: (Num a,Ord a) => [[a]] -> [[[a]]]
solve mat = construct_sub mat $ max_sub_dim $ scanl1 min $ reduce_dim mat
时间复杂性 该算法在O(m×n)中运行,m为行数,n为列数,以构造矩阵的维度

所有的子矩阵都需要O(m2×n)来构造,因此算法在O(m2×n)中运行

我们可以转换方法,在列而不是行上运行。因此,如果我们使用的是行数与列数相差很大的矩阵,我们可以首先计算最小值(可选地进行转换),从而使m成为两个矩阵中最小的一个

潜在优化点 我们可以通过构造子映射使算法更快