• 最长非递减子序列,Python实现


    1. from time import time
    2. from bisect import bisect
    3. from random import choices, seed
    4. from itertools import combinations
    5. def func1(seq):
    6. # 暴力穷举,从最长的子序列开始查找,大约耗时5小时
    7. for n in range(len(seq)-1, 0, -1): # 依次查找长度为len(seq-1),len(sqe-1)-1,....3,2,1
    8. for sub in combinations(seq,n): # 枚举出seq中所有的长度为n的序列,元素原来的先后顺序不变
    9. if list(sub) == sorted(sub):
    10. return sub # 因为是从最长向最短判断的,产生返回的肯定是长度最长的
    11. def func2(seq):
    12. # 获取可能的最大长度,缩小后面循环的范围,大约耗时1小时
    13. # 比fun1的优点是先判断出最大可能长度
    14. m = 0
    15. for i in range(len(seq)-1):
    16. if seq[i+1]>seq[i]:
    17. m = m+1
    18. if seq[-1] > seq[-2]:
    19. m = m+1
    20. for n in range(m+1, 0, -1):
    21. for sub in combinations(seq, n):
    22. if list(sub) == sorted(sub):
    23. return sub
    24. def func3(seq):
    25. # 查找最长非递减子序列的长度,直接确定后面组合时的长度,4秒
    26. # 动态规划法,查表
    27. length = [1]*len(seq)
    28. for index1, value1 in enumerate(seq): # 如果前面有更小的元素,就更新当前元素为终点的子序列长度
    29. for index2 in range(index1):
    30. if seq[index2] <= value1: # 存在前面数小于本轮待比较数
    31. length[index1] = max(length[index1], length[index2]+1) # 迭代是从0开始的,length最小的序号会最先确定长度
    32. m = max(length)
    33. for sub in combinations(seq, m):
    34. if list(sub) == sorted(sub):
    35. return sub
    36. def func4(seq):
    37. # 查找最长非递减子序列的长度,直接确定后面组合时的长度,3.66秒
    38. # 比func3的优点时,先排除掉无效子序列,减少第2步比较数量
    39. length = [1]*len(seq)
    40. for index1, value1 in enumerate(seq):
    41. for index2 in range(index1):
    42. if seq[index2] <= value1:
    43. length[index1] = max(length[index1], length[index2]+1)
    44. m = max(length)
    45. for sub in combinations(seq, m):
    46. # 测试每个子序列中是否有违反顺序的相邻元素,避免对整个子序列排序
    47. for i,v in enumerate(sub[:-1]):
    48. if sub[i] > sub[i+1]:
    49. break
    50. else:
    51. return sub
    52. def func5(seq):
    53. # 查找最长非递减子序列的长度,直接确定后面组合时的长度,3.7秒
    54. # [7,1,2,5,3,4,0,6,2]
    55. # sub = [1,2,3,4,6]
    56. # sub = [7]
    57. # sub = [1]
    58. # sub = [1,2,5]
    59. # sub = [1,2,3]
    60. # sub = [1,2,3,4]
    61. # sub = [0,2,3,4]
    62. # sub = [0,2,3,4,6]
    63. # sub = [0,2,3,4,6]
    64. sub = []
    65. m = 0
    66. # 循环结束后,m为最大非递减序列的长度,但sub并不是要求的子序列
    67. for value in seq:
    68. index = bisect(sub, value) # 使用bisect,要求sub必须为有序排列
    69. if index == m:
    70. sub.append(value)
    71. m = m + 1
    72. else:
    73. sub[index] = value
    74. for sub in combinations(seq, m):
    75. # 测试每个子序列中是否有违反顺序的相邻元素,避免对整个子序列排序
    76. for i,v in enumerate(sub[:-1]):
    77. if sub[i] > sub[i+1]:
    78. break
    79. else:
    80. return sub
    81. def func6(seq):
    82. # 空间换时间,用来存放当前元素为终点的非递减子序列(暂未理解)
    83. sub = [[num] for num in seq]
    84. for index1, value1 in enumerate(seq[1:], start=1):
    85. for index2 in range(index1):
    86. if seq[index2] <= value1:
    87. for each in sub[index2]:
    88. if isinstance(each, int):
    89. each = [each]
    90. sub[index1].append(each + [value1])
    91. # 只保留以当前元素为终点的最长非递减子序列
    92. sub[index1][1:] = [max(sub[index1][1:], default=[], key=len)]
    93. sub = list(map(lambda items: max(items[1:],default=[],key=len),sub))
    94. return max(sub, key=len)
    95. def main():
    96. seed(20231106) # 填充种子,随机生成数据相同
    97. data = choices(range(1000), k = 35) # 从0-9999数据中随机取35个数据
    98. for func in (func3,func4,func5,func6):
    99. start = time() # 取LNDS前时刻
    100. for _ in range(1):
    101. r = func(data) # 类似与函数指针
    102. print(time()-start) # 打印取数耗时,单位ms
    103. print(r) # 打印LNDS
    104. if __name__ == '__main__':
    105. main()

    引用位置(不带注释):周末花了10小时把最长非递减子序列算法速度提高了几十亿倍

  • 相关阅读:
    Ansible
    java--进制详解
    「基础知识」带你深度剖析路由器和交换机!
    注册D8读卡器COM组件
    基于Matlab使用雷达资源管理有效跟踪多个机动目标仿真(附源码)
    物联网省/国赛AIOT智能家居全流程演示
    【模板】2-SAT
    问题:remote: HTTP Basic: Access denied
    Java Web 学习笔记(三) —— Maven 基础
    测试零基础如何进入大厂?一场面试教会你(附面试题解析)
  • 原文地址:https://blog.csdn.net/yyjbluesword/article/details/134267629