在jacobson和vo提出的计算完全最长增长子序列(lis)的方法中,我在理解节点结构方面遇到了一个问题。
这是报纸上的伪代码:
什么意思
节点是一个辅助数组,对于L中的每个元素,它包含一个元素的记录,该元素在该元素之前以增加的子序列记录。函数newnode()构造这些记录并将它们链接到有向图中。在算法的最后,我们可以从L的最大元素中搜索以恢复sigma的LIS。
? 你将如何实现这个结构?
我必须构造一个有向图,它的序列的所有元素都是顶点(加上一个零顶点)和边“\ SigMai-I>S”,然后搜索最长的L(结束于nIL)元素的路径吗?有没有更有效的方法来获得完整的lis?
我的第二个问题:这个算法是否和"Heaviest Increasing/Common Subsequence Problems"中描述的算法一样快?如果不是:我可以修改维基百科的算法来计算论文中描述的最重的公共子序列吗?
最佳答案
我用一个数组实现这个数组,用结构共享实现一个单独的链表。在通用C++中,
#include <algorithm>
#include <iostream>
#include <memory>
#include <utility>
#include <vector>
template <typename T>
struct Node {
explicit Node(const T& e) : element(e) {}
T element;
std::size_t index = 0;
Node* previous = nullptr;
};
template <typename T, typename Compare>
std::vector<T> LongestIncreasingSubsequence(const std::vector<T>& elements,
Compare compare) {
if (elements.empty()) {
return {};
}
std::vector<std::unique_ptr<Node<T>>> node_ownership;
node_ownership.reserve(elements.size());
std::vector<Node<T>*> tableau;
for (const T& element : elements) {
auto node = std::make_unique<Node<T>>(element);
auto it = std::lower_bound(tableau.begin(), tableau.end(), node.get(),
[&](const Node<T>* a, const Node<T>* b) {
return compare(a->element, b->element);
});
if (it != tableau.begin()) {
auto previous = it[-1];
node->index = previous->index + 1;
node->previous = previous;
}
if (it != tableau.end()) {
*it = node.get();
} else {
tableau.push_back(node.get());
}
node_ownership.push_back(std::move(node));
}
Node<T>* longest = *std::max_element(
tableau.begin(), tableau.end(),
[](Node<T>* a, Node<T>* b) { return a->index < b->index; });
std::vector<T> result(longest->index + 1);
for (; longest != nullptr; longest = longest->previous) {
result.at(longest->index) = longest->element;
}
return result;
}
int main() {
for (int x : LongestIncreasingSubsequence(
std::vector<int>{3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3},
std::less<int>())) {
std::cout << x << '\n';
}
}
如果您有幸使用垃圾收集语言,您可以忽略
node_ownership
和std::move
的业务。这是一个python版本。
import bisect
def longest_increasing_subsequence(elements):
elements = list(elements)
if not elements:
return []
# Build the tableau
tableau_elements = []
tableau_indexes = []
predecessors = []
for i, element in enumerate(elements):
j = bisect.bisect_left(tableau_elements, element)
predecessors.append(tableau_indexes[j - 1] if j > 0 else None)
if j < len(tableau_elements):
tableau_elements[j] = element
tableau_indexes[j] = i
else:
tableau_elements.append(element)
tableau_indexes.append(i)
# Find the subsequence lengths
lengths = []
for i, predecessor in enumerate(predecessors):
lengths.append(1 if predecessor is None else lengths[predecessor] + 1)
# Extract the best subsequence
best = max(range(len(lengths)), key=lambda i: lengths[i])
subsequence = []
while best is not None:
subsequence.append(elements[best])
best = predecessors[best]
subsequence.reverse()
return subsequence
print(longest_increasing_subsequence([3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3]))