用c语言如何求最长上升子序列

用c语言如何求最长上升子序列

用C语言求最长上升子序列的方法包含动态规划、二分查找、递归等,其中,动态规划是最为常见和直观的方法。动态规划方法通过逐步找到每个位置的最长上升子序列,最后再从这些结果中找到最大的那个。接下来,我们将详细介绍动态规划方法求解最长上升子序列的过程,并给出相应的C语言代码实现。

一、动态规划方法

动态规划方法是求解最长上升子序列问题的经典方法。其基本思路是:对于每个位置i,计算以i结尾的最长上升子序列的长度。具体步骤如下:

1、初始化DP数组

首先,我们需要一个DP数组dp,其中dp[i]表示以第i个元素结尾的最长上升子序列的长度。初始时,所有元素的最长上升子序列长度都是1,因为每个元素本身就是一个长度为1的上升子序列。

int n = sizeof(arr) / sizeof(arr[0]);

int dp[n];

for (int i = 0; i < n; i++) {

dp[i] = 1;

}

2、更新DP数组

接下来,我们需要遍历数组,对于每个元素arr[i],检查之前的所有元素arr[j](其中j < i)。如果arr[j] < arr[i],则说明arr[i]可以接在以arr[j]结尾的上升子序列后面,从而构成一个新的上升子序列。此时,我们更新dp[i]的值:

for (int i = 1; i < n; i++) {

for (int j = 0; j < i; j++) {

if (arr[j] < arr[i] && dp[j] + 1 > dp[i]) {

dp[i] = dp[j] + 1;

}

}

}

3、找出最长的上升子序列长度

在更新完DP数组后,我们只需要找到dp数组中的最大值,即为最长上升子序列的长度。

int lis = 0;

for (int i = 0; i < n; i++) {

if (dp[i] > lis) {

lis = dp[i];

}

}

二、完整代码示例

下面是完整的C语言代码示例,展示了如何使用动态规划方法求解最长上升子序列问题:

#include <stdio.h>

int longestIncreasingSubsequence(int arr[], int n) {

int dp[n];

for (int i = 0; i < n; i++) {

dp[i] = 1;

}

for (int i = 1; i < n; i++) {

for (int j = 0; j < i; j++) {

if (arr[j] < arr[i] && dp[j] + 1 > dp[i]) {

dp[i] = dp[j] + 1;

}

}

}

int lis = 0;

for (int i = 0; i < n; i++) {

if (dp[i] > lis) {

lis = dp[i];

}

}

return lis;

}

int main() {

int arr[] = {10, 22, 9, 33, 21, 50, 41, 60, 80};

int n = sizeof(arr) / sizeof(arr[0]);

printf("Length of longest increasing subsequence is %dn", longestIncreasingSubsequence(arr, n));

return 0;

}

三、时间复杂度分析

动态规划方法的时间复杂度为O(n^2),其中n是数组的长度。虽然这种方法的时间复杂度较高,但其实现简单且易于理解,适用于中小规模的数据集。

四、优化方法——二分查找

为了进一步优化时间复杂度,可以结合二分查找来实现。这种方法将时间复杂度降低到O(n log n),适用于较大规模的数据集。其核心思想是在构建一个存储当前上升子序列的数组时,通过二分查找来找到插入位置,从而保持数组的有序性。

1、初始化辅助数组

我们使用一个辅助数组tail,其中tail[i]表示长度为i+1的上升子序列的最后一个元素。初始时,tail数组为空。

int tail[n];

int length = 0;

2、更新辅助数组

我们遍历原数组,对于每个元素arr[i],使用二分查找找到其在tail数组中的插入位置。如果arr[i]大于tail数组中的所有元素,则将其添加到tail数组的末尾;否则,替换相应位置的元素。

for (int i = 0; i < n; i++) {

int left = 0, right = length;

while (left < right) {

int mid = (left + right) / 2;

if (tail[mid] < arr[i]) {

left = mid + 1;

} else {

right = mid;

}

}

tail[left] = arr[i];

if (left == length) {

length++;

}

}

3、最终结果

length变量即为最长上升子序列的长度。

五、完整代码示例(优化方法)

下面是结合二分查找的优化方法的完整代码示例:

#include <stdio.h>

int longestIncreasingSubsequence(int arr[], int n) {

if (n == 0) {

return 0;

}

int tail[n];

int length = 0;

for (int i = 0; i < n; i++) {

int left = 0, right = length;

while (left < right) {

int mid = (left + right) / 2;

if (tail[mid] < arr[i]) {

left = mid + 1;

} else {

right = mid;

}

}

tail[left] = arr[i];

if (left == length) {

length++;

}

}

return length;

}

int main() {

int arr[] = {10, 22, 9, 33, 21, 50, 41, 60, 80};

int n = sizeof(arr) / sizeof(arr[0]);

printf("Length of longest increasing subsequence is %dn", longestIncreasingSubsequence(arr, n));

return 0;

}

六、总结

通过上述两种方法,我们可以有效地解决求最长上升子序列的问题。动态规划方法简单直观,但时间复杂度较高;结合二分查找的优化方法则大大降低了时间复杂度,适用于较大规模的数据集。根据具体应用场景选择合适的方法,可以更高效地解决问题。

在实际项目管理中,管理和跟踪项目任务的进展同样需要高效的方法。推荐使用研发项目管理系统PingCode通用项目管理软件Worktile,它们能够帮助团队更好地协作和管理任务,提高工作效率和项目成功率。

通过掌握这些算法和工具,不仅能够解决具体的编程问题,还能提升整体项目管理能力,从而在实际工作中获得更好的表现。

相关问答FAQs:

1. 什么是最长上升子序列?

最长上升子序列是指在一个给定序列中,找到一个最长的子序列,使得这个子序列中的元素按照顺序递增。

2. 如何用C语言编写求最长上升子序列的算法?

可以使用动态规划的方法来解决这个问题。定义一个数组dp,其中dp[i]表示以第i个元素结尾的最长上升子序列的长度。然后遍历整个序列,对于每个元素,从前面的元素中找到比它小的元素,更新dp[i]的值为dp[j]+1(其中j < i)中的最大值。最后,遍历dp数组,找到最大的值即为最长上升子序列的长度。

下面是一个简单的示例代码:

#include <stdio.h>

int findLongestIncreasingSubsequence(int arr[], int n) {
    int dp[n];
    int maxLen = 1;

    for (int i = 0; i < n; i++) {
        dp[i] = 1;
        for (int j = 0; j < i; j++) {
            if (arr[i] > arr[j] && dp[j] + 1 > dp[i]) {
                dp[i] = dp[j] + 1;
            }
        }
        if (dp[i] > maxLen) {
            maxLen = dp[i];
        }
    }

    return maxLen;
}

int main() {
    int arr[] = {3, 2, 5, 1, 4, 6};
    int n = sizeof(arr) / sizeof(arr[0]);

    int longestIncreasingSubsequence = findLongestIncreasingSubsequence(arr, n);
    printf("The length of the longest increasing subsequence is %dn", longestIncreasingSubsequence);

    return 0;
}

3. 如何优化求最长上升子序列的算法的性能?

上述动态规划的算法的时间复杂度为O(n^2),可以通过使用二分查找来优化算法的性能。定义一个辅助数组tails,其中tails[i]表示长度为i+1的最长上升子序列的最后一个元素的值。遍历整个序列,对于每个元素,使用二分查找找到它在tails数组中应该插入的位置,然后更新tails数组。最后,tails数组的长度即为最长上升子序列的长度。

下面是一个优化后的示例代码:

#include <stdio.h>

int findLongestIncreasingSubsequence(int arr[], int n) {
    int tails[n];
    int len = 1;
    tails[0] = arr[0];

    for (int i = 1; i < n; i++) {
        if (arr[i] < tails[0]) {
            tails[0] = arr[i];
        } else if (arr[i] > tails[len - 1]) {
            tails[len] = arr[i];
            len++;
        } else {
            int left = 0, right = len - 1;
            while (left < right) {
                int mid = left + (right - left) / 2;
                if (tails[mid] < arr[i]) {
                    left = mid + 1;
                } else {
                    right = mid;
                }
            }
            tails[left] = arr[i];
        }
    }

    return len;
}

int main() {
    int arr[] = {3, 2, 5, 1, 4, 6};
    int n = sizeof(arr) / sizeof(arr[0]);

    int longestIncreasingSubsequence = findLongestIncreasingSubsequence(arr, n);
    printf("The length of the longest increasing subsequence is %dn", longestIncreasingSubsequence);

    return 0;
}

希望以上解答对您有帮助!如果还有其他问题,请随时提问。

文章包含AI辅助创作,作者:Edit2,如若转载,请注明出处:https://docs.pingcode.com/baike/1091420

(0)
Edit2Edit2
免费注册
电话联系

4008001024

微信咨询
微信咨询
返回顶部