单调递增子序列问题——集成问题
"""
Longest Increasing Subsequence(LIS)单调递增子序列问题:给定一个无序的数组,求该数组中存在的最长的单调递增序列
这是一种典型的动态规划问题,其中dp[i]表示num[i]对应的最长递增训练个数;
base case:dp[i]=1,表示num[i]对应的最长递增子序列是它本身
状态转移矩阵:for j in range(i): max(dp[i], dp[j] + 1),表示位于数组num的第i个索引前面的所以小于num[i]对应值的最长索引
"""
#问题1:最长递增子序列的长度
def longest_increasing_subsequence_length(list_num):
#输入数组进行基本的判断
if list_num is None:
return 0
if len(list_num) < 2:
return len(list_num)
size = len(list_num)
dp = [1 for _ in range(size)] #初始化状态转矩阵,并设定base case
for i in range(size):
for j in range(i):
if list_num[i] > list_num[j]:
dp[i] = max(dp[i], dp[j] + 1)
res = 0
for i in range(len(dp)):
res = max(res, dp[i])
return res
# 基于二分查找的方式
def bst_function(list_num):
if list_num is None:
return 0
if len(list_num) < 2:
return len(list_num)
length = len(list_num)
top = [0 for i in range(length)]
piles = 0
for i in range(length):
target = list_num[i]
left = 0
right = piles
while left < right:
mid = left + int((right - left) / 2)
if target < top[mid]:
right = mid
elif target > top[mid]:
left = mid + 1
elif target == top[mid]:
right = mid
if left == piles: piles += 1 #注意:此处不能写成if left == right,因为左侧全部遍历完,才能添加新的堆
top[left] = target
return piles
#问题2:最长递增子序列的个数
def longest_increasing_subsequence_num(list_num):
if list_num is None:
return 0
if len(list_num) < 2:
return len(list_num)
size = len(list_num)
dp_length = [1 for i in range(size)] #记录递增子序列的最大长度
dp_count = [1 for i in range(size)] #记录list_num[i]当前最长长度对应的个数
max_length = 0 #全局最长递增子列的长度
for i in range(1, size):
for j in range(i-1, -1, -1):
if list_num[i] > list_num[j]:
if dp_length[j] + 1 > dp_length[i]:
dp_length[i] = dp_length[j] + 1
dp_count[i] = dp_count[j]
elif dp_length[j] + 1 == dp_length[i]: #备注:此处千万不能采用else,应为小于的情况也会累加
dp_count[i] += 1
max_length = max(max_length, dp_length[i]) #记录全局的最长序列
sum = 0
for i in range(len(dp_length)):
if max_length == dp_length[i]:
sum += dp_count[i] #将整个列表对应的最长序列的个数累加起来
return sum
#问题3:求出最长递增子序列的一组
def longest_increasing_subsequence(list_num):
if list_num is None:
return None
if len(list_num) < 2:
return [list_num]
size = len(list_num)
dp_length = [1 for _ in range(size)]
dp_set = [[list_num[i]] for i in range(size)]
max_length = 0
for i in range(1, size):
tmp = dp_set[i]
for j in range(i-1, -1, -1):
if list_num[i] > list_num[j]:
if dp_length[j] + 1 >= dp_length[i]:
dp_length[i] = dp_length[j] + 1
dp_set[i] = dp_set[j] + tmp
max_length = max(max_length, dp_length[i])
res = []
for i in range(len(dp_length)):
if dp_length[i] == max_length:
res.append(dp_set[i])
return res
#问题4:求出最长递增子序列的集合
# def longest_increasing_subsequence_set(list_num):
# if list_num is None:
# return None
# if len(list_num) < 2:
# return [list_num]
# size = len(list_num)
# dp_length = [1 for _ in range(size)]
# dp_set = [[[list_num[i]]] for i in range(size)]
# max_length = 0
# for i in range(1, size):
# tmp = dp_set[i]
# for j in range(i-1, -1, -1):
# if list_num[i] > list_num[j]:
# if dp_length[j] + 1 >= dp_length[i]:
# dp_length[i] = dp_length[j] + 1
# dp_set[i] = dp_set[j] + tmp
# max_length = max(max_length, dp_length[i])
#
# res = []
# for i in range(len(dp_length)):
# if dp_length[i] == max_length:
# res.append(dp_set[i])
# return res
"""
Q:给定一些标记了宽度和高度的信封,宽度和高度以整数对形式 (w, h) 出现。当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。
请计算最多能有多少个信封能组成一组“俄罗斯套娃”信封(即可以把一个信封放到另一个信封里面)。
说明:
不允许旋转信封。
示例:
输入: envelopes = [[5,4],[6,4],[6,7],[2,3]]
输出: 3
解释: 最多信封的个数为 3, 组合为: [2,3] => [5,4] => [6,7]。
"""
def solution_envelope(list_num):
list_new = sorted(list_num, key = lambda x:(x[0], -x[1])) #先对宽【0】进行顺序排列,对长【1】进行倒序排列(解决宽一样也无法放入的问题)
list_new_1 = []
for i in list_new:
list_new_1.append(i[1]) #获取排序后,列对应的数组
res = longest_increasing_subsequence_length(list_new_1) #对列对应的数组求单调递增序列的个数即可
return res
if __name__ == "__main__":
list_num = [10,9,2,5,3,7,101,108]
res = longest_increasing_subsequence_length(list_num)
print(res)
res2 = longest_increasing_subsequence_num(list_num)
print(res2)
res3 = longest_increasing_subsequence(list_num)
print(res3)
list_num1 = [[5,4],[6,4],[6,7],[2,3]]
res4 = solution_envelope(list_num1)
print(res4)
posted on 2021-12-15 09:55 random_boy 阅读(145) 评论(0) 收藏 举报
浙公网安备 33010602011771号