最长上升子序列

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

输入

复制
5
2 2
2 4
3 3
2 5
4 5

输出

复制
4

具体做法就是先对长排序,然后对宽进行最长上升(不递减)子序列的搜索。参考知乎的一个解答如下,但仍然复杂度太高,期待更加有效的解法。

 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)

 

posted @ 2019-07-06 16:09  三年一梦  阅读(480)  评论(0)    收藏  举报