Longest increasing subsequence)

Source: Internet
Author: User

A typical dynamic planning problem that companies like to use for interview pen questions. There are also many articles on the Internet to discuss this issue, but I think the most important thing about this issue is that, these discussions seem to be unclear and unpleasant. Therefore, I want to thoroughly discuss this issue and hope to clarify the details of this issue.

There are usually recursive solutions to the dynamic planning problem, which is no exception. AI {A1, A2 ,......, AI} longest incrementing sub-sequence, need to first find the sequence Ai-1 {A1, A2 ,......, Ai-1} to each element (A1, A2 ,......, Ai-1) as the longest ascending sequence of the largest element, and then compare all these Ascending Sequences with AI, if a length of M is at the end of the element AJ (j <I) smaller than Ai, add the element AI to this incremental sub-sequence to obtain a new sequence with a new length of m + 1. Otherwise, the length remains unchanged, compare the length of all I sequences after processing. The longest sequence is the longest ascending subsequence. For example, for sequence a {35,
36, 39, 3, 15, 27, 6, 42} when processing the ninth element (27), take 35, 36, 39, 3, 15, 27, 6. The longest ascending sequence of the last element is
35
35, 36
35, 36, 39
3
3, 15
3, 15, 27
3, 6
When 10th new elements are added to 42, these sequences become
35, 42
35, 36, 42
35, 36, 39,42,
3, 42
3, 15, 42
3,15, 27,42
3, 6, 42

The longest ascending sequence is (,) and (,), so the length of the longest ascending subsequence of sequence a is 4, at the same time, there is more than one incremental sub-sequence with a length of 4 in.

The idea of this algorithm is very simple. If we want to obtain the longest incrementing sub-sequence of the AI sequence, we need to calculate all the elements of the Ai-1 as the longest incrementing sequence of the largest element, ......, After this process is reversed, the recursive algorithm is obtained. A1, A2 ,......, Until the launch of AI,

The Code is as follows:

Unsigned int Liss (const int array [], size_t length, int result []) {unsigned int I, J, K, Max; // Variable Length array parameter, new feature of c99, used to record the maximum incremental sequence length of each element as the maximum element. Unsigned int Liss [length]; // an array of precursor elements, records the front nodes of the element in the ascending sequence with this element as the largest element. It is used to print the sequence with unsigned int pre [length]; for (I = 0; I <length; ++ I) {Liss [I] = 1; Pre [I] = I;} for (I = 1, max = 1, K = 0; I <length; ++ I) {// find the longest ascending subsequence with array [I] as the last element for (j = 0; j <I; ++ J) {// If non-decreasing subsequence is required You only need to change array [J] <array [I] to <=, // if you want to decrease the subsequence, you only need to change it to> If (array [J] <array [I] & Liss [J] + 1> Liss [I]). {Liss [I] = Liss [J] + 1; Pre [I] = J; // obtain the length of the subsequence with the longest increment currently, and the position of the last element of the subsequence if (max <Liss [I]) {max = Liss [I]; k = I ;}}}} // output sequence I = max-1; while (pre [k]! = K) {result [I --] = array [k]; k = pre [k];} result [I] = array [k]; return Max ;}

This function calculates the length of the longest incrementing sub-sequence of the array with the length of length, and returns the result as the return value. The actual sequence is saved in the result array, this function uses the c99 variable-length array parameter feature (this feature is good). Students who do not support c99 can use malloc to apply for two array variables in the function. The time complexity of the function is O (NN). Next we will introduce how to reduce the time complexity to the O (nlogn) improved algorithm.

In the basic algorithm, we find that when we need to calculate the longest ascending sub-sequence of the first I element, the former I-1 element as the ascending sequence of the largest element, regardless of the length, or the maximum element value, there is no rule to follow, so when I began to calculate the first element can only traverse the previous I-1 elements, to find the J value that meets the conditions, making AJ <AI, among all J that meet the condition, the ascending subsequence with AJ as the largest element is the longest. Is there a more efficient way to find such an element, AJ? Actually there is, but a new concept needs to be used. In the sequence example we mentioned earlier, we will find that when we calculate 10th elements, the first nine elements form the largest headers

35
35, 36
35, 36, 39
3
3, 15
3, 15, 27

3, 6

There are two subsequences with a length of 3, three subsequences with a length of 2, and two subsequences with a length of 1, so one sequence, there may be more than one incremental sub-sequence with a length of N, but one of all sub-sequences with a length of N is special, that is, the smallest incremental sub-sequence of the largest element (the concept of a very wide mouth). In the above example, the sequence (3), (3, 6), (3, 5, 27) satisfies such a property, they are the smallest element in the ascending sub-sequence with a length of 1, 2, and 3 (until 10th elements are processed). As the elements are added, sub-sequences that meet the conditions are constantly changing. If these subsequences are arranged from short to long by length, put their largest elements together to form a new sequence B {b1, b2 ,...... BJ}, then sequence B meets B1
<B2 <...... <BJ. This relationship is easy to describe. Assume that bxy represents the Y element in the ascending sequence of sequence a with the length of X. Obviously, if the element BMM> BNN exists in sequence B, m <n indicates that the maximum element of the subsequence BN is smaller than the maximum element of the BM. Because the sequence is strictly incrementing, BNM <BNN, from bn0 to BNM, a new incremental sequence with m length is formed. Because BMM> BNN, BMM> BNM, this indicates that in sequence B, an incremental sub-sequence with a length of m and a maximum element of BNM <BMM exists, which is consistent with the sequence definition, BMM is the smallest sequence of M elements in all incremental sequences with the length of M. Therefore, all elements in sequence B are strictly incrementing. We have found such a strictly incrementing sequence, which makes it possible for us to use the strictly incrementing sequence and find the element BK whose maximum element is just less than AJ by using binary search, add AJ to the end of the sequence to form a new sequence with a length of K + 1 but the maximum element is smaller than BK + 1, replacing the previous BK + 1, if AJ is larger than all elements in bn, it indicates that an incremental sequence with AJ as the largest element and length n + 1 is found, add AJ as the nth + 1 element of BN + 1. From B1, we can find the longest incremental subsequence of sequence a in the time of O (nlogn.

The theoretical explanation is boring. Let's look at an example. The steps to improve the algorithm are described in sequence {6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6:

At the beginning of the program, the maximum length of the incremental sequence is 1 (each element is an incremental sequence with a length of 1 ), when processing 2nd elements, it is found that 7 is larger than the maximum element of the longest incremental sequence 6. Therefore, 6, 7 are combined to generate an incremental sequence with a length of 2, it indicates that an incremental sequence with a length of 2 has been found, which is processed sequentially to 5th elements (10). In this process, the changing process of array B is

6
6, 7
6, 7, 8
6, 7, 8, 9
6, 7, 8, 9, 10

Start to process the smallest element whose 6th elements are 1 and find the smallest element greater than 1. It is found that it is the maximum element 6 of the subsequence whose length is 1, 1 is an incremental sequence with a smaller length of 1 and 6 with 1 to form a new array, 10. Then, find the smallest element greater than 7th elements (2) and find 7, indicating that there is a sequence with a length of 2, and its last element 2 is smaller than 7. Replace 7 with 2, execute the statement in sequence until all elements are processed, generate a new array 1, 2, 3, 4, 5, and add 6 to the B array to form the longest ascending subsequence with a length of 6.

In this process, the change process of array B is

1, 7, 8, 9, 10
1, 2, 8, 9, 10
1, 2, 3, 9, 10
1, 2, 3, 4, 10
1, 2, 3, 4, 5
1, 2, 3, 4, 5, 6

When processing 10th elements (5), the traditional algorithm needs to view 9 elements (6, 7, 8, 9, 10, 1, 2, 3, 4 ), the improved algorithm only needs to use binary search for two elements (3, 4) in array B. It can be seen that the improved algorithm is quite negative.

The implementation of this algorithm is as follows:

Unsigned int lissex (const int array [], size_t length, int result []) {unsigned int I, J, K, L, Max; // Stack Array parameter, new Feature of c99. The Liss array here has different meanings from the previous function, liss [I] The record length is I + 1 // The Position of the last element (maximum element) of the smallest subsequence in the ascending subsequence in the array unsigned int Liss [length]; // an array of precursor elements used to print the sequence unsigned int pre [length]; Liss [0] = 0; for (I = 0; I <length; ++ I) {pre [I] = I ;}for (I = 1, max = 1; I <length; ++ I) {// find such J so that all In J, J has the smallest J = 0, K = max-1, while (k-j> 1) {L = (J + k)/2; if (array [Liss [l] <array [I]) {J = L ;}else {k = L ;}} if (array [Liss [J] <array [I]) {J = K ;} // if the value of array [Liss [0] is greater than that of array [I], if (j = 0) {// an equal sign must be added here, when multiple equal minimum values exist in the array, fill the minimum value in the Liss [1] position if (array [Liss [0]> = array [I]) {Liss [0] = I; continue ;}} // if the value of array [Liss [Max-1] is smaller than that of array [I], if (j = max-1) {If (array [Liss [J] <array [I]) {Pre [I] = Liss [J]; Liss [Max ++] = I; continue;} Pre [I] = Liss [J-1]; liss [J] = I;} // output ascending subsequence I = max-1; k = Liss [Max-1]; while (pre [k]! = K) {result [I --] = array [k]; k = pre [k];} result [I] = array [k]; return Max ;}

The idea of this algorithm can be clever and significantly improved in terms of time complexity, but at the same time it is much more difficult to implement than the popular algorithm. Here we will explain:

  • In the algorithm, in order to obtain the actual sequence, array B saves not the minimum value of the maximum element of the ascending sequence whose length is J, but the position of this value in input array, if you only want to find the length of the longest incrementing sub-sequence, array B can directly Save the value that meets the condition Element
  • The purpose of the result of the binary search is to find such a j so that J can obtain the minimum value among all J values that meet a [B [J]> A [I, however, in binary search, two special cases may occur: All elements in array B are not smaller than a [I], and all elements in array B are smaller than those in array a [I, special processing is required for these two situations.
  • If all elements in B are not smaller than a [I], update a [I] to B [0 ].
  • If all elements in B are smaller than a [I], update the value to the position of B [Max] and increase the value of Max by 1, it indicates that the result is longer than the longest incremental sequence currently.
  • In other cases, when updating the front node of the new node, note that the front node of the current element is B [J-1], instead of pre [B [J], pay special attention to this. The latter seems reasonable, but it may have been changed in the previous update.

Performance Comparison: a random array with a length of 5000. On my machine, the improved algorithm speed is improved by nearly 200 times. This shows the importance of improved algorithms in program performance. However, traditional algorithms are not without value,

First, traditional algorithms can be used to verify the correctness of the improved algorithms. Uncertainty in binary search is quite a headache. Secondly, if the longest non-descending subsequence and the longest descending subsequence are required, the traditional algorithm is very intuitive (which has been annotated), and the algorithm is improved, at the very least, I don't know how to change it at a glance.

I have searched the internet for this improved algorithm. When I search nodes that meet the condition in binary search, I have talked a few times to complete the function, however, I have encountered some type of sequence that cannot be processed without any exception. I don't know if I have any deviation in understanding the algorithm.

Afterwards, after studying this question, there were two issues left over and there was no answer for the moment. I would like to share with you

  • For a sequence a, there may be more than one ascending subsequence. The traditional algorithm finds the ascending subsequence with the minimum maximum subscript (first appearance) among all ascending subsequences, the improved algorithm finds the smallest ascending sub-sequence of the maximum value. Is the incremental sub-sequence of the improved algorithm the smallest element in all the longest ascending sub-sequences, I think it is very likely, but I haven't figured out how to prove it.
  • What is the mathematical expectation of the longest ascending subsequence of random number sequence a with different elements?

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.