我希望能够在haskell中创建一个程序,它可以从一个数字列表中找到一个不断增加的子序列(尚未完成,这部分是为每个子列表计算最长的子序列在该子列表中的内容)。该程序基本上取自诸如
之类的输入1
5
1 2 9 6 8
其中第一行是测试用例的数量,第二行是特定测试用例中的数字,第三行是测试用例本身。它正在寻找测试用例中的多个增加序列。以下是我到目前为止的情况:
main = do
inputCases <- getLine
let cases = (read inputCases :: Int)
forM [1..cases] $ \num -> do
inputNumbers <- getLine
let numbers = (read inputNumbers :: Int)
something <- getLine
let singlewords = words something
list = f singlewords
let hello = grid numbers numbers 0
let second = hello
print list
forM [0..numbers] $ \check -> do
forM [check..numbers] $ \check2 -> do
let val = 1
let keeper = val
forM [check..check2] $ \check3 -> do
let val = getVal hello list keeper check check2 check3
let keeper = val
return()
print check
print check2
print val
let hello = updateMatrix second val (check, check2)
let second = hello
f :: [String] -> [Int]
f = map read
grid :: Int -> Int -> a -> [[a]]
grid x y = replicate y . replicate x
getVal :: [[Int]] -> [Int] -> Int -> Int -> Int -> Int -> Int
getVal m b second x y z =
if b!!z < b!!y && 1+m!!x!!z > second then 1+m!!x!!z
else second
updateMatrix :: [[a]] -> a -> (Int, Int) -> [[a]]
updateMatrix m x (r,c) =
take r m ++
[take c (m !! r) ++ [x] ++ drop (c + 1) (m !! r)] ++
drop (r + 1) m
然而,我的问题是,一旦程序退出ForM循环,它就不会保存变量&#34; hello&#34;或者在for循环中声明的任何内容。有没有更好的方法呢?递归会在这种情况下起作用吗?我不太确定如何实施 lis [i] [j]将保持{a [i],...,a [j]}
中增长最长的子序列的长度这是我要翻译的python代码。鉴于此代码,除了我目前正在尝试的方式之外,还有更好的方法吗?
T = int(input())
for t in range(0, T):
n = int(input())
a = list(map(int, input().split()))
lis = [[0 for j in range(0, n)] for i in range(0, n)]
for i in range(0, n):
for j in range(i, n):
val = 1
for k in range(i, j):
if(a[k] < a[j] and 1 + lis[i][k] > val):
val = 1 + lis[i][k]
lis[i][j] = val
答案 0 :(得分:3)
在我的另一个答案中,我讨论了您在forM
循环中稍后如何存储信息以便检索的问题的答案。在这个答案中,我将讨论来自其他语言的for
循环的惯用语翻译;通常这是不在Haskell中生成forM
循环。
因为这是一个很好的编程练习,我不想放弃答案 - 自己解决问题有很多快乐和学习。但我确实想说明一种替代方法。为了保留我用Python代码编写的翻译的所有有趣内容,我将以稍微程式化的方式解决一个稍微容易的问题:而不是lis[i][j]
给出索引之间最长的增长子序列的长度{{1在原始列表中,我们将i
给出原始列表中索引j
和lis[i][j]
之间的最大值。
这个想法将是这样的:我们不是迭代索引i
和j
,而是迭代从i
开始的后缀,然后是从{{j
开始的后缀前缀。 1}}并以i
结束。首先,我们将完成在每个中缀表达式上调用i
的天真的事情。所以:
j
例如,我们可以在ghci中的示例列表中尝试:
maximum
请注意,这里的形状存在差异:在Python中我们生成了一个正方形结果,这里我们生成一个三角形结果,省略了与原始列表的实际中缀块不对应的无用条目。 (如果由于某种原因确实需要平方结果,则很容易重新引入虚拟值。)
这已经很不错了,非常惯用;但是,有一部分Python代码还没有很好地捕获:Python代码重用以前计算的值来进行一些动态编程。这也可以用于上面的代码,虽然它确实需要一些心理体操,你看到它的前几次。我们将使用惰性和递归来计算以后的结果。
这里的想法是在我们遍历后缀时保持滚动最大值,合并为我们在后缀的最大值列表中使用我们在后缀中看到的新值。所以:
import Data.List
maxes0 a =
[ [ maximum inf
| inf <- tail (inits suff)
]
| suff <- init (tails a)
]
我们可以在ghci中看到它的作用是一样的:
> maxes0 [1,2,9,6,8]
[[1,2,9,9,9],[2,9,9,9],[9,9,9],[6,8],[8]]
你可以结合这两个想法(通过懒惰+递归使已经计算的位可用,并通过嵌套列表推导使中缀列表可用)来产生完全纯粹的Python代码的惯用翻译,没有提到在任何地方列出索引,并且不使用maxes1 a =
[ let row = head suff : zipWith max row (tail suff)
in row
| suff <- init (tails a)
]
。
答案 1 :(得分:1)
forM
返回一个值列表,每个输入元素在它所递送的列表中各一个,以及您在forM
函数体中计算的任何值。因此,您可以使用通常的do
- 符号绑定语法从循环体中提取信息。这是一个简单的例子,询问用户是否要加倍列表中的每个数字:
import Control.Monad
vals = [1..5]
main = do
vals' <- forM vals $ \val -> do
v <- getLine
return (if v == "yes" then val*2 else val)
print vals'
运行它的一个例子:
> main
yes
yes
no
no
yes
[2,4,3,4,10]
尽管此示例为简单起见返回了数字,但您可以通过这种方式从每次循环迭代中返回任意感兴趣的信息。