时间复杂度为O(nlogn)的最长单调递增子序列

本文介绍了一种求解最长递增子序列长度问题的有效算法。通过使用二分查找法来优化传统方法,该算法能在O(n log n)的时间复杂度内解决问题。文章提供了完整的C++实现代码,并通过实例展示了如何利用此算法找出一个序列中最长递增子序列的长度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写一记,其中利用二分查找法,具体分析见编程之美。

#include <iostream>
using namespace std;
#define N	20

int binarySearch(int src[], int des, int low, int high)
{
	int i = low, j = high;
	while (low < high)
	{
		int mid = (low + high) / 2;
		if (des > src[mid])
		{
			low = mid+1;
		}
		else if (des < src[mid])
		{	
			high = mid;
		}
		else
			return mid;
	}
	return low;
}

int LIS_Length(int X[], int len)
{
	int LIS[N];
	LIS[0] = INT_MIN;
	for (int i = 1; i < N; i++)
	{
		LIS[i] = INT_MAX;
	}

	for (int i = 0; i < len; i++)
	{
		int loc;
		loc = binarySearch(LIS, X[i], 0, len);
		LIS[loc] = X[i];
	}

	int count = 0;
	for (int i = 1; i <= len; i++)
	{
		if (LIS[i] < INT_MAX)
		{
			cout<<LIS[i]<<" ";
			count++;
		}
	}
	cout<<endl;
	return count;
}

int main()
{
	int X[] = {3, 2, 5, 6, 1, 4, 7};
	int len = 7;
	cout<<LIS_Length(X, len);
}


 

### 最长单调递增子序列 (LIS) 算法实现 #### 动态规划方法 \(O(n^2)\) 动态规划是一种解决 LIS 问题的经典方法。通过构建一个辅助数组 `dp`,记录以每个位置结束的最长递增子序列长度。 以下是基于动态规划的方法: ```python def lis_dp(arr): if not arr: return 0 n = len(arr) dp = [1] * n # 初始化 dp 数组,初始值均为 1,因为最短的递增子序列为单个元素本身 for i in range(1, n): # 遍历每一个元素作为结尾的情况 for j in range(i): # 查找前面所有可能构成递增关系的位置 if arr[j] < arr[i]: dp[i] = max(dp[i], dp[j] + 1) # 更新当前最大长度 return max(dp) # 返回全局最大值即为整个序列的 LIS 长度 ``` 这种方法的时间复杂度为 $O(n^2)$[^1],适用于较小规模的数据集。 --- #### 基于二分查找优化的方法 \(O(n \log n)\) 为了进一步降低时间复杂度,可以通过维护一个有序列表来加速计算过程。具体思路如下: - 使用一个额外数组 `tails` 来存储潜在的递增子序列候选者。 - 对于每个新加入的数,如果它大于 `tails` 中的所有数,则将其追加到末尾;否则,利用二分查找找到第一个不小于它的数并替换之。 下面是具体的代码实现: ```python from bisect import bisect_left def lis_nlogn(arr): tails = [] # 存储递增子序列的最小可能尾巴 for num in arr: idx = bisect_left(tails, num) # 找到 num 应该插入的位置 if idx == len(tails): # 如果 num 大于 tails 中所有的数,则扩展 tails tails.append(num) else: # 否则更新对应位置上的数值 tails[idx] = num return len(tails) # tails 的长度即为 LIS 的长度 ``` 此版本的时间复杂度降到了 $O(n \log n)$[^1],适合处理大规模数据输入场景。 --- #### 示例运行 假设我们有以下测试用例: ```python if __name__ == "__main__": test_array = [10, 9, 2, 5, 3, 7, 101, 18] print("Using DP method:", lis_dp(test_array)) # 输出应为 4 print("Using Binary Search method:", lis_nlogn(test_array)) # 输出也应为 4 ``` 两个函数均返回相同的结果——表示原始数组中的最长递增子序列长度为 4(例如 `[2, 3, 7, 101]` 或其他符合条件的组合)。 --- ### 总结 两种方法各有优劣: - **动态规划**易于理解和实现,但其平方级时间复杂度使其仅限用于中小规模问题; - **二分查找优化版**显著提升了效率至线性对数级别,在实际应用中更为高效。 最终选择取决于具体需求以及性能约束条件下的权衡考虑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值