最长上升/下降子序列

版权声明:本文为博主原创文章,可以转载但必须注明出处。 https://blog.csdn.net/nirendao/article/details/81263414

最长上升/下降子序列

给定一个数组,求其中最长的上升子序列的长度(求最长下降子序列也是一样的算法)。这个问题还可以这么问:求最长上升子序列是什么。
这是一个动态规划的问题。以第i个节点处为最后一个节点的最长上升序列是什么呢?自然是要查看之前 i-1 个节点最长上升序列的长度。如果以节点 x (1<=x<=i-1) 为最终节点的最长上升子序列为 n ,并且 x 节点的值小于 i 节点的值,那么以 i 节点为最终节点的最长上升序列就可以是 n+1 长度了。如此,只要知道 1 到 i-1 节点的情况,就能知道以 i 为最终节点的最长上升子序列的长度。这就相当于状态转移方程了。而第1个节点的最长上升序列就是1.

这个是O(n^2)的算法复杂度。实际上还可以做到O(nlogn)的复杂度,本文没有继续进一步挖掘了。
写成程序也不难,如下:

int array[] = {10, 34, 56, 32, 45, 66, 88, 43, 99};
int size = sizeof(array)/sizeof(int);
vector<int> records(size, 1);  // 记录以每个节点为最终节点时的最长上升子序列的长度,全部初始化为1,因为序列中只有自己一个节点时就是1

for (int i=0; i<size; ++i) {
    for (int j=0; j<i; ++j) {
        if (array[j] < array[i]) {
            if (records[j]+1 > records[i]) {
                records[i] = records[j] + 1;
            }
        }
    }
}

以上的程序可以计算出最长上升子序列的长度了,但具体最长上升子序列是什么呢?其实依据上述的程序,也很好计算了。比如,给每个节点对应一个链表,记录以该节点为最终节点时的最长上升序列。最后一个节点的链表,就是最长上升子序列了。当然,最长上升子序列可能并不是唯一的,这里只去找到其中一个即可。
完整代码如下:(记录最长上升子序列的链表的代码可能并不是最优的,只是代码可读性上较好)

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


void print_vector(vector<int>& vec)
{
    for (auto i : vec){
        cout << i << ", ";
    }
    cout << endl;
}

struct Node {
    int data;
    Node *next;
    Node(int d):data(d){next = NULL;}
};

Node* clone_list(Node *head) 
{
    if (head == NULL) return NULL;

    Node *p = NULL;
    Node *h = NULL;
    bool first = true;

    while(head != NULL) {
        Node *tmp = new Node(head->data);

        if (first == true) {
            h = tmp;
            p = tmp;
            first = false;
        } 
        else {
            p->next = tmp;
            p = p->next; 
            p->next = NULL;
        }
        head = head->next; 
    }
    return h;
}


void delete_list(Node *head) 
{
    if (head == NULL) return; 
    while (head != NULL) {
        Node *tmp = head;
        head = head->next;
        delete tmp;
    }
}

Node * add_one_node(Node *head, int data)
{
    Node *tmp = new Node(data);
    if (head == NULL) return tmp;

    Node *hh = head;
    while(head->next != NULL) head = head->next;
    head->next = tmp;
    return hh;
}

void print_list(Node *head)
{
    while(head != NULL) {
        cout << head->data << ", ";
        head = head->next;
    }
    cout << endl;
}


int main()
{
    int array[] = {10, 34, 56, 32, 45, 66, 88, 43, 99};
    int size = sizeof(array)/sizeof(int);

    vector<int> records(size, 1);
    vector<Node *> lists(size, NULL);
    Node *a0 = new Node(array[0]);
    lists[0] = a0;

    for (int i=0; i<size; ++i) {
        for (int j=0; j<i; ++j) {
            if (array[j] < array[i]) {
                if (records[j]+1 > records[i]) {
                    records[i] = records[j] + 1;

                    delete_list(lists[i]);
                    lists[i] = clone_list(lists[j]);
                    add_one_node(lists[i], array[i]);
                }
            }
        }
    }

    print_vector(records);
    for (int i=0; i<size; i++)
        print_list(lists[i]);

    return 0;
}

(完)

猜你喜欢

转载自blog.csdn.net/nirendao/article/details/81263414