技术访谈:MxN矩阵中最长的非减少子序列

时间:2013-03-21 16:40:05

标签: algorithm

我最近在技术面试中被问到了这个问题。这是我的解决方案。 http://pastebin.com/JMVHcfRq我犯了错误还是有更好的解决方案?

  

通过您选择的语言中的矩形数字网格中的相邻非重复单元格(包括对角线)查找最长非递减序列的长度。解决方案应该处理任意宽度和高度的网格   例如,在下面的网格中,可以跟踪的一条合法路径(尽管不是最长的)是0-> 3-> 7-> 9,其长度为4。   8 2 4
  0 7 1
  3 7 9
  该路径只能连接相邻的位置(您无法连接8 - > 9)。该实施例的最长可能序列的长度为6,通过描述路径0-> 2-> 4-> 7-> 7-> 9或1-> 2-> 4->。 7-&将7-> 8
。   用你选择的语言编写一个方法,用一个矩形的数字网格作为输入,并返回最长的序列长度作为输出。

4 个答案:

答案 0 :(得分:6)

您可以使用有向图来模拟您的问题:

如果两个单元格C i,j <,则每个单元格都是图形中的顶点,并且存在来自C i,j →C k,m 的边缘/ sub>,C k,m 是相邻的,C i,j &lt; ç<子> K,M

现在你的问题是找到这个图中最长的路径,但是这个图是Directed非循环图,因为问题说矩阵中没有重复的数字也是“&lt;”关系是反对称的。所以你的问题减少到找到有向无环图中最长的路径,这很容易通过首先进行拓扑排序然后找到最长的路径。例如,见this

<强>更新 乍一看,我认为不可能有平等的邻居,但现在我看到是可能的,在上面的图形结构我们应该替换&lt;使用&lt; =然后确定图形不是非循环但仍然有问题等于在此图中找到最长路径。

P.S1:如果我有这个最长路径问题的任何多项式答案,我会把它带到这里,但可能通过这种问题分类更容易搜索它。

P.S2:作为评论中提到的mbeckishlongest path problem在一般图形中是NP-Hard,但我认为在这种特殊情况下可以在P中解决,但我没有现在是精确的算法。

P.S3:我做了一点研究,我看到了,Hamiltonian path in grid graph is NP-Complete,所以看来你的问题也是NP-Complete(我现在没有减少,但它们彼此非常接近)。

答案 1 :(得分:2)

在最坏的情况下,你的解决方案需要指数时间(矩阵的大小)。

要加快速度,请使用memoization或自下而上dynamic programming

答案 2 :(得分:1)

同样使用n dijkstra调用(将其反向查找最大路径),您可以在O(n ^ 3)中解决它。使用最大堆可以将其降低到0(n ^ 2 log n)。构建图形时,仅为邻居创建边缘,这些邻域是> =当前顶点。

我尝试了拓扑排序,但我在图中找到了循环。需要检查我的代码。

答案 3 :(得分:0)

在我看来,不测试的起始索引是那些包含在较长路径中的索引,其中包括所有索引允许的“下一索引”的所有列表。

所以我首先为每个索引映射了允许的下一个索引,并从启动索引组中删除所有索引以进行测试:

*Main> indexesIncludedInLongerPaths
[2,0,4,6,1,7,8] (numbers 4,8,7,3,2,7,9)

留下了两个要测试的索引:

*Main> indexesToTest
[3,5] (numbers 0,1)

之后,我搜索了那些起始索引的所有路径并返回最长的路径。

*Main> nonDesc matrix
[[1,2,4,7,7,9],[0,2,4,7,7,9]]


哈斯克尔代码:

import Data.List (nub, delete, sortBy, groupBy)

matrix = [8,2,4
         ,0,7,1
         ,3,7,9]::[Int]
m = 3
n = 3

neighbors index
  | index == 0           = [1,m]
  | index == m - 1       = [m-2, 2*m-1, 2*m-2]
  | index == m*n - 1     = [m*n-2, m*(n-1)-1, m*(n-1)-2]
  | index == m*(n-1)     = [m*(n-1)+1, m*(n-2), m*(n-2)+1]
  | index < m            = [index+1, index-1, index+m, index+m-1, index+m+1]
  | index > m*(n-1)      = [index+1, index-1, index-m, index-m-1, index-m+1]
  | mod index m == 0     = [index+1, index-m, index+m, index-m+1, index+m+1]
  | mod (index+1) m == 0 = [index-1, index-m, index+m, index-m-1, index+m-1]
  | otherwise            = [index+1, index-1, index-m, index+m
                           ,index-m+1, index-m-1, index+m+1, index+m-1]

indexesIncludedInLongerPaths = 
  nub $ concatMap (\x -> [a | a <- neighbors x
                              ,matrix!!x <= matrix!!a]) [0..length matrix-1]

indexesToTest = 
  foldr (\a b -> delete a b) [0..length matrix-1] indexesIncludedInLongerPaths

nonDesc matrix = solve indexesToTest [[]] where
  solve []     result = last $ groupBy (\a b -> length a == length b)
                        $ sortBy (\a b -> compare (length a) (length b)) 
                        $ map (\x -> map (\y -> matrix!!y) x) (concat result)
  solve (x:xs) result = 
    let paths = solve' [x] 
    in solve xs (paths:result)         
      where solve' y = 
              let b = [a | a <- neighbors (last y)
                                ,notElem a y
                                ,matrix!!(last y) <= matrix!!a]
              in if null b
                    then return y
                    else do a <- b
                            solve' (y ++ [a])