最长上升子序列
1. 这道题源于牛客网上的一道笔试题,中间步骤用到了最长上升子序列的思想。
题目描述
小明有一袋子长方形的积木,如果一个积木A的长和宽都不大于另外一个积木B的长和宽,则积木A可以搭在积木B的上面。好奇的小明特别想知道这一袋子积木最多可以搭多少层,你能帮他想想办法吗?
定义每一个长方形的长L和宽W都为正整数,并且1 <= W <= L <= INT_MAX, 袋子里面长方形的个数为N, 并且 1 <= N <= 1000000.
假如袋子里共有5个积木分别为 (2, 2), (2, 4), (3, 3), (2, 5), (4, 5), 则不难判断这些积木最多可以搭成4层, 因为(2, 2) < (2, 4) < (2, 5) < (4, 5)。
输入描述:
第一行为积木的总个数 N
之后一共有N行,分别对应于每一个积木的宽W和长L
输出描述:
输出总共可以搭的层数
具体做法就是先对长排序,然后对宽进行最长上升(不递减)子序列的搜索。参考知乎的一个解答如下,但仍然复杂度太高,期待更加有效的解法。
1 N = int(input())
2 temp = []
3 for i in range(N):
4 temp.append(list(map(int, input().split())))
5 temp = sorted(temp, key=lambda x:x[0])
6 def lengthOfLIS(s):
7 if len(s)<=1:return len(s)
8 dp = [0]*len(s)
9 for i in range(len(s)):
10 max_len = 0
11 for j in range(i):
12 if s[i]>=s[j]:
13 if dp[j]>max_len:
14 max_len = dp[j]
15 dp[i] = max_len+1
16 # print(dp)
17 return max(dp)
18
19 print(lengthOfLIS([i[1] for i in temp]))
最长子序列算法思想:(动态规划)
1.状态
f[i]表示前 i 个元素, 并且以第 i 个元素为结尾的,最长子序列长度是多少
2.方程
f[i] = for j :
if(A[i] > A[j])
{
A[i] = Math.max(A[j] + 1, A[i])
}
对于 i 前面的所有点 j ,如果 A[i] 大于 A[j] 的话,说明可以继续在 A[j] 的后面加上 A[i] ,
则f[i] = f[j] + 1
重新将上面的思路整理了下,还是很清晰的。原题见leetcode 300 Longest Increasing Subsequence

图源:慕课网
class Solution:
def lengthOfLIS(self, nums) -> int:
if len(nums)<2: return len(nums)
res = [1]*len(nums)
for i in range(1,len(nums)):
for j in range(i):
if nums[i]>nums[j]: # 如果当前元素比之前的元素大,则考虑将当前的元素放到后面
res[i] = max(res[i], res[j]+1)
return max(res)

浙公网安备 33010602011771号