您提供的链接包含一个使用堆栈数据结构的解决方案。每种语言中的示例都会改变堆栈,使用带有索引的数组并通过索引访问数组的元素。所有这些操作在 Haskell 中并不常见。
让我们考虑以下解决方案:
type Quote = Int
type Quotes = [Quote]
type Span = [Int]
stockSpanWithStack :: Quotes -> Span
stockSpanWithStack quotes = calculateSpan quotesWithIndexes []
where
quotesWithIndexes = zip quotes [0..]
calculateSpan [] _ = []
calculateSpan ((x, index):xs) stack =
let
newStack = dropWhile (\(y, _) -> y <= x) stack
stockValue [] = index + 1
stockValue ((_, x):_) = index - x
in
(stockValue newStack) : (calculateSpan xs ((x, index):newStack))
让我们将其与 Python 解决方案进行比较:
# Calculate span values for rest of the elements
for i in range(1, n):
# Pop elements from stack whlie stack is not
# empty and top of stack is smaller than price[i]
while( len(st) > 0 and price[st[0]] <= price[i]):
st.pop()
# If stack becomes empty, then price[i] is greater
# than all elements on left of it, i.e. price[0],
# price[1], ..price[i-1]. Else the price[i] is
# greater than elements after top of stack
S[i] = i+1 if len(st) <= 0 else (i - st[0])
# Push this element to stack
st.append(i)
对于堆栈解决方案,我们需要带有索引的元素。可以这样模仿:
quotesWithIndexes = zip quotes [0..]
引号列表是递归迭代的,而不是在每次循环迭代中修改堆栈,我们可以使用修改后的值调用函数:
calculateSpan ((x, index):xs) stack =
Python中的以下行(堆栈元素的弹出,小于当前值):
while( len(st) > 0 and price[st[0]] <= price[i]):
st.pop()
在 Haskell 中可以重写为:
newStack = dropWhile (\(y, _) -> y <= x) stack
以及股票价值的计算:
S[i] = i+1 if len(st) <= 0 else (i - st[0])
可以解释为:
stockValue [] = index + 1
stockValue ((_, x):_) = index - x
下面说过,修改变量的状态并不常见,例如S[i] = ... 或st.append(i)。但是我们可以用新的堆栈值递归调用函数并将当前结果添加到它之前:
(stockValue newStack) : (calculateSpan xs ((x, index):newStack))
从技术上讲,我们推入列表的开头并删除列表的第一个元素,因为这是在 Haskell 中处理列表的惯用方式和更高效的方式。