1 算法描述
有一个n个数组成的数列,取一个连续的子序列,并且这个子序列还必须得满足:最多只改变一个数,就可以使得这个连续的子序列是一个严格上升的子序列,这个连续子序列最长的长度是多少。
2 算法分析
-
算法输入:长度为n的随机整数数列,该数列无序、整体有序、部分有序
-
算法核心:查找最大子数列集合,从最大集开始向最小集查找,找到则退出。查找子集时使用窗口滑动的方式遍历所有子集,并且判断子集是否符合条件。
-
算法输出:最大子数列或者最大子数列的长度
3 算法目标
算法运行的目标是最小化系统资源开销(包括处理器资源开销与内存资源开销)以及最小耗时(算法运行时长)。
4 算法设计
算法输入的数列需要先实行标准化处理,当前算法是使用二维数组的数据结构对数列实现标准化封装,第二维的数组元素需要保存原始值、处理状态以及其他扩展值。本章节主要分为如下两部分:数据结构设计以及算法逻辑设计,数据结构设计是对数列的输入输出实行标准化的封装,算法逻辑设计主要描述实现算法的步骤流程。
4.1 数据结构设计
数组的元素描述如下表所示:
第一维 | 数组元素指向第二维的数组 | |
第二维 | Index=0,原始值 | Index=1,计算状态值 |
4.2 算法逻辑设计
窗口滑动函数流程设计:
-
获取输入数列,按照以上的数据结构标准化处理
-
从窗口长度等于数列的长度n开始迭代
-
滑动窗口开始(滑动步长为1)
-
获取当前窗口子数列
-
判断是否满足子数列的条件(调用条件函数),满足则退出到6步骤,不满足则滑入3步骤(下一窗口)
-
滑动窗口结束,滑入2步骤的下一长度的窗口滑动周期
-
结束窗口迭代,返回满足上一窗口期的长度
条件函数流程设计:
-
从当前窗口中获取对应的子数列判断是否符合严格升序
-
因为最多修改一个数值,所以假设子数列删除一个数值后,剩下的子数列符合严格升序
-
迭代子数列,按照迭代次序,每次迭代,删除在该迭代次序对应的索引位置的数值元素,判断剩下的子数列是否符合严格升序
-
符合3步骤的子数列,判断删除位的相邻两个元素是否符合严格升序
-
符合4步骤的子数列是待查询的子数列
主函数流程设计:
-
随机生成一个整数数列
-
标准化数列
-
执行窗口滑动函数
-
执行条件判断函数
-
输出符合查询条件的子数列以及其长度
5 算法实现
5.1 程序语言
算法使用Java语言实现
5.2 程序示例
窗口函数:
条件函数:
主函数:
数据输出:
第一行是输入的随机数列,第二行是合法子数列的长度,第三行是合法子数列,只需要修改合法子数列中的数值22为55与87之间的任何一个数值即可。
6 算法验证
本算法验证测试使用代码覆盖率测试方法。
6.1 测试用例
6.2 执行用例
测试用例通过率100%,代码覆盖率100%。
7 算法效率
7.1 时间复杂度
由代码可知该算法的时间复杂度等于O(N的多次方)。
7.2 空间复杂度
该算法使用二维数组,其空间复杂度是常数。
7.3 性能测试
输入数列长度 | 输出数列长度 | 耗时 |
100 | 6 | 37毫秒 |
200 | 6 | 381毫秒 |
300 | 7 | 1449毫秒 |
400 | 6 | 4385毫秒 |
500 | 7 | 11524毫秒 |
600 | 9 | 21481毫秒 |
由以上的性能测试可知,每增加100个数值元素,耗时呈现几何级增长,在这种的情况下需要进行算法优化。
7.4 算法优化
在算法窗口滑动中以多线程的方式启动多个worker工作线程处理条件函数。