我最近在技术面试中被问到了这个问题。这是我的解决方案。 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
。 用你选择的语言编写一个方法,用一个矩形的数字网格作为输入,并返回最长的序列长度作为输出。
答案 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:作为评论中提到的mbeckish,longest 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])