c++ 什么是最省时的方法来找到长度LIS的连续性?[重复]

y0u0uwnf  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(98)

此问题在此处已有答案

Finding All possible Longest Increasing subsequence(4个答案)
5天前关闭。
给定一个数组(向量)序列。我需要一个方法或一个修复可能会找到所有与最长递增序列长度的递增连续性。例如:**[1,3,2,5,2]**应该输出:1 3 5和1 2 5
1 3 5是第一个LIS长度3。然后下一个是1 2 5。
我已经实现了一些它适用于较小示例的东西,但一旦我有一个较大的序列数组(大小:1000+),程序就永远需要。
这是我的LIS长度的函数:它使用动态编程,工作速度非常快

int findLISLength(const std::vector<int>& sequence, size_t n) {
    std::vector<int> lisEnd(n + 1, 0);
    std::vector<int> parent(n, 0);
    int length = 0;

    for (int i = 0; i < n; ++i) {
        int low = 1;
        int high = length;
        while (low <= high) {
            int mid = (low + high) / 2;
            if (sequence[lisEnd[mid]] < sequence[i])
                low = mid + 1;
            else
                high = mid - 1;
        }
        int pos = low;
        parent[i] = lisEnd[pos - 1];
        lisEnd[pos] = i;

        if (pos > length)
            length = pos;
    }

    return length;
}

字符串
这是我的函数,用于查找给定长度的所有递增的连续性。这是时间复杂度非常高的地方,因为有三个for循环。我也尝试了递归,它需要同样多的时间。

std::vector<std::vector<int>> getAllIncreasingSubsequences(const std::vector<int>& sequence, size_t length) {
    std::vector<std::vector<int>> result;
    std::vector<std::vector<std::vector<int>>> dp(sequence.size());

    for (size_t i = 0; i < sequence.size(); ++i) {
        dp[i].push_back({ sequence[i] });
        for (size_t j = 0; j < i; ++j) {
            if (sequence[i] > sequence[j]) {
                for (const auto& subseq : dp[j]) {
                    if (subseq.size() + 1 <= length) {
                        auto newSeq = subseq;
                        newSeq.push_back(sequence[i]);
                        dp[i].push_back(newSeq);
                    }
                }
            }
        }
    }

    for (const auto& subseq : dp) {
        for (const auto& sub : subseq) {
            if (sub.size() == length) {
                result.push_back(sub);
            }
        }
    }

    return result;
}


我从文件中读取序列号,然后调用函数。
序列为:
[43629 88099 89706 22748 1174 68526 8869 61079 64279 2965 56809 3540 94669 72740 94999 18126 ...]

int main(){
    size_t L = findLISLength(sequence, N);
    vector<vector<int>> 
        increasingSubsequences = getAllIncreasingSubsequences(sequence, L);
    //print subsequence
    cout << "L: " << L << endl;
    cout << "Increasing subsequences: " << endl;
    for (auto& subsequence : increasingSubsequences) {
        for (auto& element : subsequence) {
            cout << element << " ";
        }
        cout << '\n';
    }
}

uz75evzq

uz75evzq1#

我不知道你的代码是如何工作的,所以我决定用一种对我来说既清楚又相当有效的方式重写。如果答案是m从长度为n的列表中增加长度为k的序列,我的算法将是O(n^2 + m*k)
注意m可以随着向量的大小呈指数增长。最坏的情况是一个结构为[2, 1, 4, 3, 6, 5, 8, 7, ..., n, n-1]的向量,那么将有2^(n/2)最大递增序列。递增序列的数量几乎可以肯定是你的代码太慢的原因。这就是为什么我边走边打印的原因。前两行给出了它有多糟糕的想法。
这是一个演示程序。

#include <iostream>
#include <vector>
using namespace std;

// Make it easy to print a vector.
template <typename S>
ostream& operator<<(ostream& os, const vector<S>& vector)
{
    // Printing all the elements
    // using <<
    for (auto element : vector) {
        os << element << " ";
    }
    return os;
}

void printAllIS(const std::vector<int>& seq) {
    size_t n = seq.size();
    int maxSize = 0;
    std::vector<int> listSize;
    std::vector<int> countLists;
    std::vector<std::vector<int>> nextIndexes;

    // initialize empty data.
    for (int i = 0; i < n; i++) {
        listSize.push_back(0);
        countLists.push_back(0);
        std::vector<int> next;
        nextIndexes.push_back(next);
    }

    // Go from the end of the sequence backwards.
    for (int i = n-1; 0 <= i; i--) {
        int size = 1;
        int count = 1;
        std::vector<int> next;

        for (int j = i+1; j < n; j++) {
            if (seq[i] < seq[j]) {
                if (size < listSize[j] + 1) {
                    // Reinitialize to only count lists of this size.
                    size = listSize[j] + 1;
                    count = 0;
                    next.clear();
                    if (maxSize < size) {
                        maxSize = size;
                    }
                }
                if (size == listSize[j] + 1) {
                    // This is a next index, record it.
                    count += countLists[j];
                    next.push_back(j);
                }
            }
        }
        // Now that we have the answer, save it.
        listSize[i] = size;
        countLists[i] = count;
        nextIndexes[i] = next;
    }

    int count = 0;
    vector<int> next;
    for (int i = 0; i < n; i++) {
        if (listSize[i] == maxSize) {
            count += countLists[i];
            next.push_back(i);
        }
    }

    // Indicate how big the answer will be.
    cout << "Size of sequences: " << maxSize << endl;
    cout << "Number of sequences: " << count << endl;

    // Indicate how big the answer will be.
    cout << "Size of sequences: " << maxSize << endl;
    cout << "Number of sequences: " << count << endl;

    /*
        The data structure for printing is 3 vectors of the same size.
        Think of it as a vector of frames with:

        - value = seq[i]
        - indexIter = iterator through nextIndexes[i]
        - indexIterEnd = nextIndexes[i].end()

        Each time we come back to a frame we discard the value. If
        iteration is done at this level, we throw away the rest of
        the frame. Otherwise we stack up frames until we are ready
        to print again.
    */
    vector<int> values;
    vector<vector<int>::iterator> indexIters;
    vector<vector<int>::iterator> indexIterEnds;

    // initialize. Note, we'll discard the value immediately.
    values.push_back(0);
    indexIters.push_back(next.begin());
    indexIterEnds.push_back(next.end());
    while (0 < indexIters.size()) {
        // Done with this value.
        values.pop_back();
        auto indexIter = indexIters.back();
        auto indexIterEnd = indexIterEnds.back();
        if (indexIter == indexIterEnd) {
            // Throw away the rest of the frame.
            indexIters.pop_back();
            indexIterEnds.pop_back();
        }
        else {
            while (true) {
                // Start stacking frames.
                int i = *indexIter;
                // Add a value - they are now equal.
                values.push_back(i);
                indexIters.back() = ++indexIter;
                indexIter = nextIndexes[i].begin();
                indexIterEnd = nextIndexes[i].end();
                if (indexIter == indexIterEnd) {
                    // Ready to print!
                    cout << values << endl;
                    // All done the printing loop.
                    break;
                }
                else {
                    // Add the rest of the next frame.
                    // The value will be added at
                    // the start of the next loop.
                    indexIters.push_back(indexIter);
                    indexIterEnds.push_back(indexIterEnd);
                }
            }
        }
    }
}

int main() {
    vector<int> vect{2, 1, 4, 3, 6, 5, 8, 7, 10, 9};
    printAllIS(vect);
}

字符串

相关问题