美文网首页
子序列问题

子序列问题

作者: 拔丝圣代 | 来源:发表于2018-01-28 19:03 被阅读0次

本篇讲解四道子序列相关题目

1. 最长摆动子序列(No. 376)


题目

摆动序列是指相邻数字的差正负交替(不包括0)。子序列是指从序列中删除一部分数字,剩余的数字保持原来的顺序不变组成的数列。
给一串序列,求它的最长摆动子序列的长度。

思路

形象地,把序列点按顺序画在坐标图上并连接,摆动序列就是一个一上一下的折线图。因此我们只要留下每个上升的最高点以及每次下降的最低点,即可得到最长子序列。也就是只留下每次连续同方向变化的最后一个点。

算法

首先确定第一次变化方向,用一个变量last_is_up表示上一次的变化方向,1为上升,-1为下降。用另一个变量length存储当前子序列长度。
从第三个数开始,遍历每个数,如果这个数与前面的变化方向不一致(即连续两次上升或下降),则长度length加一,变化方向反向;否则不变。
最后返回length即为结果。

注意

注意序列前几个数可能相同,不能通过前两个数判断首次变化方向。

代码

class Solution:
    def wiggleMaxLength(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if len(nums) < 2:
            return len(nums)
        last_is_up = None  # 变化方向最初不能确定
        length = 1
        for i in range(1, len(nums)):
            d = nums[i] - nums[i-1]  # d是变化值
            if last_is_up is None:  # 先确定首次变化方向
                if nums[i] != nums[i-1]:
                    last_is_up = 1 if d > 0 else -1
                    length += 1
            elif d * last_is_up < 0:  # 变化方向不一致
                length += 1
                last_is_up *= -1
        return length

2. 最长连续递增子序列 (No.674)


题目

给一个序列,求最长连续递增子序列的长度

示例

Input: [1,3,5,4,7]
Output: 3
Explanation: The longest continuous increasing subsequence is [1,3,5], its length is 3. 
Even though [1,3,5,7] is also an increasing subsequence, it's not a continuous one where 5 and 7 are separated by 4. 

思路

从第二个元素往后扫,比上一个元素大则长度加一,否则清零重新累加。这个过程中长度的最大值即为所求

代码

class Solution:
    def findLengthOfLCIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if len(nums) < 2:
            return len(nums)
        ml = 1  # 最大长度
        l=1  # 当前长度
        for i in range(1, len(nums)):
            if nums[i] > nums[i-1]:  # 若递增,则长度加一
                l += 1
            else:  # 否则当前长度置为1
                ml = max(ml, l)
                l=1
        ml = max(ml, l)
        return ml

3. 最长递增子序列 (No.300)


题目

给一个序列,求最长递增子序列的长度

思路

动态规划。定义一个状态函数length(k),表示以第k个数为结尾的最长递增自序列的长度。length(1)=1,当k>1时,依次求length(k),具体求法为:
遍历k之前的所有数,如第x个数,如果小于第k个数,则第k个数可以接在这个数之后,形成新的递增子序列,长度为length(x) + 1。所有这些长度中最长的即为length(k)。所有的length之中,最大的就是最长递增子序列的长度。

示例

Given [10, 9, 2, 5, 3, 7, 101, 18],
The longest increasing subsequence is [2, 3, 7, 101], therefore the length is 4.

算法

用一个列表length表示上述状态函数。从前往后扫描序列,填充length列表。求法如下:
length(k) = max(length(x) + 1)
其中,x为前k-1个数中所有小于第k个数的位置
得到的length数组中,最大的数即为所求

代码

class Solution:
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if len(nums) < 2:
            return len(nums)
        length = [1]
        for i in range(1, len(nums)):
            psb = 1  # 可能的长度
            for j in range(i):
                if nums[j] < nums[i]:
                    psb = max(psb, length[j] + 1)  # 可能的长度中最大的
            length.append(psb)  # 填充length数组
        return max(length)

4. 最长递增子序列数量 (No.673)


题目

求上述最长递增子序列的数量。其中,不同位置的相同数字组成的两个子序列算两个。

示例

Input: [1,3,5,4,7]
Output: 2
Explanation: The two longest increasing subsequence are [1, 3, 4, 7] and [1, 3, 5, 7].
Input: [2,2,2,2,2]
Output: 5
Explanation: The length of longest continuous increasing subsequence is 1, and there are 5 subsequences' length is 1, so output 5.

思路

与上一题类似,只是除了用length表示以当前元素结尾的最长递增子序列的长度之外,另外用count表示这上的序列的个数,最后找出所有length为最大值的数对应count值之和。

算法

与上一题类似,用两个数组lengths和counts表示以第i个数为结尾的最长递增子序列的长度和数量。在更新lengths的同时,更新counts。counts的更新方法是:所有当前数字之前的lengths最大对应的counts之和即为当前counts。最后所有lengths最大的counts之和即为所求。

代码

class Solution(object):
    def findNumberOfLIS(self, nums):
        N = len(nums)
        if N <= 1: return N
        lengths = [0] * N #lengths[i] 表示以第i个数结尾的最长递增子序列的长度
        counts = [1] * N #count[i] 表示以第i个数结尾的最长递增子序列的数量

        for j, num in enumerate(nums):
            for i in range(j):
                if nums[i] < nums[j]:
                    if lengths[i] >= lengths[j]:
                        lengths[j] = 1 + lengths[i]
                        counts[j] = counts[i]
                    elif lengths[i] + 1 == lengths[j]:
                        counts[j] += counts[i]

        longest = max(lengths)
        return sum(c for i, c in enumerate(counts) if lengths[i] == longest)

相关文章

  • 算法(04)动态规划

    零钱问题 背包问题 最长公共子序列 最长公共子串 最长上升子序列 最大连续子序列和

  • 子序列问题

    最长公共子序列 最长上升/下降/不升/不降子序列

  • 子序列问题

    本篇讲解四道子序列相关题目 1. 最长摆动子序列(No. 376) 题目 摆动序列是指相邻数字的差正负交替(不包括...

  • 子序列问题

    判断序列S是否是序列T的子序列 解析:典型的双指针问题 Code

  • 子序列问题

    一些子序列问题 (持续补充) 最长上升子序列 题目 dp数组,每一个数组记录前面最长的上升序列长度。 和标程对比 ...

  • 最长公共子序列问题解析

    问题解读 最长公共子序列问题,就是找出两个字符串中,存在的最长的子序列 什么是子序列呢?子序列不同于公共子串,子串...

  • 动态规划常见面试题

    子序列类型编辑距离 最长递增子序列 最大子数组 最长公共子序列 背包问题0-1背包问题 子集背包问题 完全背包问题...

  • 算法思想之动态规划(六)——最长上升子序列问题

    前言 今天我们继续讨论经典的动态规划问题之最长上升子序列问题。 最长上升子序列问题 问题描述 给定一个数字序列A,...

  • 动态规划之"最大连续子序列"

    最大连续子序列问题 问题定义: 给定K个整数的序列{ N1, N2, ..., Nk },其任意连续子序列可表示为...

  • 最长公共子序列问题

    问题描述: 求两个字符序列的公共最长子序列。 最长公共子串 在回到子序列问题之前,先来了解一下子串的问题。例如,H...

网友评论

      本文标题:子序列问题

      本文链接:https://www.haomeiwen.com/subject/gbqzaxtx.html