精华内容
下载资源
问答
  • 之前做过的最长上升子序列的题只是不需要输出这个序列http://www.cnblogs.com/Scale-the-heights/p/4333346.html ...要输出路径其实也很简单,就开个数组f[]把所有数字在最长上升子序列中第一次出现的位置记录...

    之前做过的最长上升子序列的题只是不需要输出这个序列http://www.cnblogs.com/Scale-the-heights/p/4333346.html

    做法就是从左到右扫一遍,可以参见http://blog.csdn.net/shuangde800/article/details/7474903

    要输出路径其实也很简单,就开个数组f[]把所有数字在最长上升子序列中第一次出现的位置记录下来,然后逆序遍历,比如我们找到最长上升子序列的长度为n,则我们从后往前找到曾经在最长上升子序列中位置为n的数字储存起来,由于扫描是从后往前的,所以这个数字一定是原序列的一个最长上升子序列中位置为n的数字。以此类推。

    详细解释可以参见http://blog.csdn.net/ouckitty/article/details/27801843

    我是用lower_bound代替了二分,时间紧迫,没时间详写了,要想详解的可以看下上面的链接,贴个代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <string>
    using namespace std;
    int num[1000010],tmp[1000010],f[1000010];
    int main()
    {
        int t;
        scanf("%d",&t);
        getchar();
        getchar();
        while(t--){
            int cnt=1;
            string str;
            while(getline(cin,str)){
                int len=str.length();
                if(len==0){
                    break;
                }
                int ans=0;
                for(int i=0;i<len;i++){
                    ans=10*ans+(str[i]-'0');
                }
                num[cnt++]=ans;
            }
            int s=0;
            for(int i=1;i<cnt;i++){
                if(s==0){
                    tmp[s++]=num[1];
                    f[1]=0;
                }
                else{
                    if(num[i]>tmp[s-1]){
                        f[i]=s;
                        tmp[s++]=num[i];
                    }
                    else{
                        int low=lower_bound(tmp,tmp+s,num[i])-tmp;
                        if(low<s){
                            tmp[low]=num[i];
                            f[i]=low;
                        }
                    }
                }
            }
            cout<<"Max hits: "<<s<<endl;
            int x=s;
            int counter=0;
            for(int i=cnt-1;i>=1;i--){
                if(f[i]==x-1){
                    tmp[counter++]=num[i];
                    x--;
                }
            }
            for(int i=counter-1;i>=0;i--){
                cout<<tmp[i]<<endl;
            }
            /*for(int i=0;i<s;i++){
                printf("%d\n",tmp[i]);
            }*/
            if(t){
                printf("\n");
            }
        }
        return 0;
    }

     

    转载于:https://www.cnblogs.com/Scale-the-heights/p/4429671.html

    展开全文
  • 题目:给定一个无序的整数数组,找到其中最长上升子序列的长度。 示例: 输入: [10,9,2,5,3,7,101,18] 输出: 4 解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。 理解:由于题目只要最长上升子序列得长度,并不...

    题目:给定一个无序的整数数组,找到其中最长上升子序列的长度。
    给定一个未经排序的整数数组,找到最长且连续的的递增序列。
    输入: [1,3,5,4,7]
    输出: 3
    解释: 最长连续递增序列是 [1,3,5], 长度为3。
    尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为5和7在原数组里被4隔开。
    理解:重点把握连续,动态规划.
    初始化:dp=[1]*n
    转移矩阵为if nums[i]>nums[j]->dp[i]=dp[j]+1。
    输出:max(dp)

    class Solution:
        def findLengthOfLCIS(self, nums: List[int]) -> int:
            n = len(nums)
            if n<=1:
                return n
            dp = [1]*n
            for i in range(1,n):
                if nums[i]>nums[i-1]:
                    dp[i] = dp[i-1]+1
            return max(dp)
    

    进阶1:给定一个无序的整数数组,找到其中最长上升子序列的长度。
    示例:
    输入: [10,9,2,5,3,7,101,18]
    输出: 4
    解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。

    理解:由于题目只要最长上升子序列得长度,并不要求实际子序列。因此可直接利用动态规划。与题一要求不同的是:这个是子序列,而不要求连续。因此需要加一层循环,遍历0-i之间的所有状态。
    初始状态为:dp[i] =1。dp[i]代表的是位置i得到的最长上升子序列的长度,因此初始化为1表示只有一个i字符满足条件得情况下则最长上升子串长度即为1。
    转移矩阵:dp[i] = max(dp[i], dp[j]+1)。j属于(0,i)。相当于两层遍历,针对0-i之间的位置j, 如果i>j, 则可更新dp[i]=dp[j]+1,当然要针对0-i之间所有的选取最大值作为位置i的状态。.
    输出:dp所有位置的最大值即可。

    class Solution:
        def lengthOfLIS(self, nums: List[int]) -> int:
            n = len(nums)
            if n==0:
                return 0
            dp =[]
            for i in range(n):
                dp.append(1)
                for j in range(i):
                    if nums[i]>nums[j]:
                        dp[i] = max(dp[i], dp[j]+1)
            return max(dp)
    

    当然还有二分+贪心的算法。核心思想为:每次都选取离最大值最近的值进行递增。

    进阶2求最长递增子序列的个数。
    输入: [1,3,5,4,7]
    输出: 2
    解释: 有两个最长递增子序列,分别是 [1, 3, 4, 7] 和[1, 3, 5, 7]。
    输入: [2,2,2,2,2]
    输出: 5
    解释: 最长递增子序列的长度是1,并且存在5个子序列的长度为1,因此输出5。
    理解:相当于求递增子序列的基础之上统计个数,因此直观理解,需要在长度的dp之上增加一个count数组统计当前位置最长子序列的个数,表示当前最长上升子序列可以得到的个数。
    初始化:当然都为1
    状态转移矩阵:在满足nums[i]>nums[j],即可以递增的情况下进行分类。1)如果dp[i]<=dp[j],即还没有基于状态j进行最长递增子序列的更新:此时更新最长递增子序列dp[i]=dp[j]=1,并且count[i]应等于count[j]。2)如果dp[i]==dp[j]+1,表明此时已经基于j进行子序列更新或者等同长度的更新,如12435中,更新5时,由3的状态得到dp[i]=4,而由4的状态也可以得到dp[i]=4,因此,需要将count[3]+count[4]:那么count[i]+=count[j]。

    def findNumberOfLIS(self, nums: List[int]) -> int:
            n = len(nums)
            if n==0:
                return 0
            dp =[]
            count = [1]*n #存储当前i结尾的最长子串的个数
            for i in range(n):
                dp.append(1)
                for j in range(i):
                    if nums[i]>nums[j]:#可以上升
                        #dp[i] = max(dp[i], dp[j]+1)
                        #新增判断
                        if dp[i] <= dp[j]:#还未上升过
                            dp[i] = dp[j] +1
                            count[i] = count[j]#由j上升的得到的i,自己个数等同于j的个数
                        elif dp[i] == dp[j]+1:#如12435中,5可以由3得到,也可以由4得到。
                            count[i] += count[j]
            max_length = max(dp)
            return sum(c for i, c in enumerate(count) if dp[i] == max_length)
    

    进阶3输出该最长上升子序列。
    思路:利用回溯法,基于最长上升子序列的输出dp[i], 及其位置。然后从后往前找dp[i]-1的位置加入到res中.

    class Solution:
        def lengthOfLIS(self, nums: List[int]) -> int:
            n = len(nums)
            if n==0:
                return 0
            dp =[]
            pos = 1
            for i in range(n):
                dp.append(1)
                for j in range(i):
                    if nums[i]>nums[j]:
                        dp[i] = max(dp[i], dp[j]+1)
                        pos = i#找出最大的那个位置,从后往前找
            deepth = max(dp)#输出最大的值
            res = []
            for j in range(pos, -1, -1):
                if dp[j] = deepth:
                    res.insert(0, nums[j])
                    deepth -=1#最长上升子序列的长度值依次减一往前找。
            return res
    
    展开全文
  • 最长上升子序列普通算法 dp[n]表示以a[n]结尾的最长上升子序列长度 显然有 dp[n]=max(dp[n],dp[i]+1) 满足a[i]<a[n],1<=i<n 实现过程时间复杂度为O(n^2) 2.O(nlogn)时间复杂度 思路是用数组lower保存最长...
    1. 最长上升子序列普通算法
      dp[n]表示以a[n]结尾的最长上升子序列长度
      显然有
      dp[n]=max(dp[n],dp[i]+1) 满足a[i]<a[n],1<=i<n
      实现过程时间复杂度为O(n^2)

    2.O(nlogn)时间复杂度

    思路是用数组lower保存最长上升子序列长度,对于当前元素a[i],若大于数组lower最后一个元素,则插入lower数组。否则,用二分在lower数组找到第一个大于a[i]的元素,并替换a[i]。整体上来说,用了贪心,因为每次的替换是让lower数组每个元素尽可能的小,这样的话就更有可能能在lower数组末尾插入元素。
    关键的是,lower数组中保存的元素并不是真正的最长上升子序列,它表示的是最长上升子序列的长度。

    那么问题来了?如何求最长上升子序列呢?
    我们可以用一个pos2数组,记录一下数组a中的每个元素在lower数组中出现的位置。然后从数组a最后一个元素开始到第一个元素,寻找到最长上升子序列。
    具体实现代码如下

    int pos2[maxn],answer[maxn];
    void LIS_quicker(int arrays[],int lower [],int n){//最长上升子序列nlogn算法+输出最长上升子序列
        lower[1]=arrays[1];
        int index=1;
        pos2[1]=1;
        for(int i=2;i<=n;i++) {
            if(arrays[i]>=lower[index]) {
                lower[++index]=arrays[i];
                pos2[i]=index;
            }else {
                int pos=upper_bound(lower+1,lower+index+1,arrays[i])-lower-1;
                lower[pos]=arrays[i];
                pos2[i]=pos;   //记录原数组中每个元素在 lower数组中出现的位置
            }
        }
        int maxx=999999; //从右往左打印,
        for(int i=n;i>=1;i--) {
            if(index==0) break;
            if(pos2[i]==index&&maxx>a[i]) { //先找第一个在lower数组index位置,再找第一个在lower数组index-1位置直到index=0
                answer[index]=i;//保存答案
                index-=1;
                maxx=a[i];
            }
        }
    
    }
    
    展开全文
  • 文章目录最长公共子序列题目描述题解最长上升子序列题目描述题解解法一解法二最长公共上升子序列题目描述题解 最长公共子序列 题目描述 给定两个长度分别为N和M的字符串A和B,求既是A的子序列又是B的子序列的字符串...

    最长公共子序列

    题目描述

    给定两个长度分别为N和M的字符串A和B,求既是A的子序列又是B的子序列的字符串长度最长是多少。
    输入格式
    第一行包含两个整数N和M。
    第二行包含一个长度为N的字符串,表示字符串A。
    第三行包含一个长度为M的字符串,表示字符串B。
    字符串均由小写字母构成。
    输出格式
    输出一个整数,表示最大长度。
    数据范围
    1≤N,M≤1000
    输入样例:
    4 5
    acbd
    abedc
    输出样例:
    3

    题解

    在这里插入图片描述

    状态计算考虑最后一个元素,分别考虑a[i], b[j] 是否在集合中,这里的集合是指既包含在a[1~i]中,又包含在b[1-j]中。0表示在,1表示不在。

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <string>
    using namespace std;
    const int N = 1010;
    
    int f[N][N];
    char a[N], b[N];
    
    int main()
    {
        int n, m;
        cin >> n >> m;
        
        cin >> a + 1 >> b + 1; //避免下标越界,起始位置从1开始
        
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= m; j++)
            {
                if(a[i] != b[j])
                {
                    f[i][j] = max(f[i - 1][j], f[i][j - 1]);
                }
                else
                {
                    f[i][j] = f[i - 1][j - 1] + 1;
                }
            }
        }
        
        cout << f[n][m] << endl;
        
        return 0;
    }
    

    最长上升子序列

    题目描述

    给定一个无序的整数数组,找到其中最长上升子序列的长度。
    示例:
    输入: [10,9,2,5,3,7,101,18]
    输出: 4
    解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。

    题解

    在这里插入图片描述

    状态计算考虑最后一个元素,判断在a[1~i]中是否有一个元素a[k]( 0 =< k <= i)小于a[i]
    小于的话就可以转移。

    解法一

     int lengthOfLIS(vector<int>& nums) {
            int n = nums.size();
            vector<int> f(n + 1, 1);
            for(int i = 0; i < n; i++)
            {
                for(int j = 0; j < i; j++)
                {
                    if(nums[j] < nums[i])
                    {
                        f[i] = max(f[i], f[j] + 1);
                    }
                }
            }
    
    
            int res = 0;
            for(int i = 0; i < n; i++) res = max(f[i], res);
    
            return res;
        }
    

    解法二

    依然是着眼于一个上升子序列的结尾的元素;
    如果已经得到的上升子序列的结尾的数越小,遍历的时候后面接上一个数,就会有更大的可能性构成一个更长的上升子序列;
    既然结尾越小越好,我们可以记录在长度固定的情况下,结尾最小的那个元素的数值,这样定义也是为了方便得到「状态转移方程」。
    为了与之前的状态区分,这里将状态数组命名为 tail。
    定义新状态(特别重要):tail[i] 表示长度为 i + 1 的所有上升子序列的结尾的最小值。

    int lengthOfLIS(vector<int>& nums) {
            int n = nums.size();
            
            if(n < 2) return n;
    
            vector<int> tail; //长度为i的上升子序列末尾元素
    
            tail.push_back(nums[0]);
            int end = 0;
            for(int i = 1; i < n; i++)
            {
                if(nums[i] > tail[end])
                {
                    tail.push_back(nums[i]);
                    end++;
                }
                else
                {
                    int l = 0, r = end;
                    while(l < r)
                    {
                        int mid = l + r >> 1;
                        if(tail[mid] < nums[i]) l = mid + 1;
                        else r = mid;
                    }
    
                    tail[l] = nums[i];
                }
            }
    
            return end + 1;
        }
    

    最长公共上升子序列

    题目描述

    熊大妈的奶牛在小沐沐的熏陶下开始研究信息题目。
    小沐沐先让奶牛研究了最长上升子序列,再让他们研究了最长公共子序列,现在又让他们研究最长公共上升子序列了。
    小沐沐说,对于两个数列A和B,如果它们都包含一段位置不一定连续的数,且数值是严格递增的,那么称这一段数是两个数列的公共上升子序列,而所有的公共上升子序列中最长的就是最长公共上升子序列了。
    奶牛半懂不懂,小沐沐要你来告诉奶牛什么是最长公共上升子序列。
    不过,只要告诉奶牛它的长度就可以了。
    数列A和B的长度均不超过3000。
    输入格式
    第一行包含一个整数N,表示数列A,B的长度。
    第二行包含N个整数,表示数列A。
    第三行包含N个整数,表示数列B。
    输出格式
    输出一个整数,表示最长公共上升子序列的长度。
    数据范围
    1≤N≤3000,序列中的数字均不超过231−1
    输入样例:
    4
    2 2 1 3
    2 1 2 3
    输出样例:
    2

    题解

    1.状态表示:
    f[i][j]代表所有a[1 ~ i]和b[1 ~ j]中以b[j]结尾的公共上升子序列的集合;
    f[i][j]的值等于该集合的子序列中长度的最大值;
    2.状态计算(对应集合划分):
    首先依据公共子序列中是否包含a[i],将f[i][j]所代表的集合划分成两个不重不漏的子集:
    不包含a[i]的子集,最大值是f[i - 1][j];
    包含a[i]的子集,将这个子集继续划分,依据是子序列的倒数第二个元素在b[]中是哪个数:
    子序列只包含b[j]一个数,长度是1;
    子序列的倒数第二个数是b[1]的集合,最大长度是f[i - 1][1] + 1;

    子序列的倒数第二个数是b[j - 1]的集合,最大长度是f[i - 1][j - 1] + 1;

    算法优化:
    优化第二层循环。因为a[i] == b[j], 第三层循环的作用是求小于b[j]的方案数,也即是求小于a[i]的方案数, 求完一个j后,剩下的j继续往后走变成j+1,但第一层循环i保持不变。即if(b[j + 1] = a[i]), 又会执行第三层循环,这时就会重复求解原来求过的数。

    #include "iostream"
    
    using namespace std;
    
    const int N = 3010;
    
    int f[N][N];
    
    int a[N], b[N];
    
    int main(){
        
        int n;
        cin>>n;
        for(int i = 1; i <= n; i++){
            cin>>a[i];
        }
        
        for(int i = 1; i <= n; i++){
            cin>>b[i];
        }
        
        //朴素算法
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= n; j++){
                f[i][j] = f[i-1][j];
                if(a[i] == b[j]){
                    int mmax = 1;
                    for(int k = 1; k < j; k++){
                        if(b[k]<b[j]){
                            mmax = max(mmax, f[i-1][k]+1);
                        }
                    }
                    
                    f[i][j] = max(f[i][j], mmax);
                }
            }
        }
        
        //优化后的算法
        /* for(int i = 1; i <= n; i++){
            int mmax = 1;
            for(int j = 1; j <= n; j++){
                f[i][j] = f[i-1][j];
                if(b[j]<a[i]) mmax = max(mmax, f[i-1][j]+1);
                if(a[i] == b[j]) f[i][j] = max(f[i][j], mmax);
                
                }
            }
        */
        
        int res = 0;
        
        for(int i = 1; i <= n; i++) res = max(res, f[n][i]);
        
        printf("%d\n", res);
         
        
        return 0;
    }
    

    链接:https://www.acwing.com/solution/content/4955/

    展开全文
  • 最长上升子序列长度和输出序列

    千次阅读 2019-05-09 22:21:48
    最长上升子序列最长上升子序列,并输出最长子序列。此文解释两种方法,dp和二分算法。并详细解释了输出最长子序列的过程。且代码精短易懂
  • 给定一个长度为N的数列,求数值严格单调递增的子序列的长度最长是多少。 输入格式 ...动态规划之最长上升子序列模型,要求输出最长上升子序列的长度,从两方面入手: 状态表示: 用一维表示状态 f[i
  • i){//递归输出下标,,,,太感动了,就是这里纠结了n个小时 if (i== 0 ) return ; else out (id[i]); cout [i].id endl; } int main() { int i, n, j, totle, w, s, pos= 0 ; i = 0 ; ...
  • 最长上升子序列(Longest Increasing Subsequence),简称LIS,也有些情况求的是最长非降序子序列,二者区别就是序列中是否可以有相等的数。假设我们有一个序列 b i,当b1 < b2 < … < bS的时候,我们称这...
  • 给定一个整数序列,找到最长上升子序列(LIS),返回LIS的长度。 说明 最长上升子序列的定义: 最长上升子序列问题是在一个无序的给定序列中找到一个尽可能长的由低到高排列的子序列,这种子序列不一定是连续...
  • 最长上升子序列问题(中等) 题目描述 给定一个无序的整数数组...可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。 你算法的时间复杂度应该为 O(n2) 。 进阶: 你能将算法的时间复杂度降低到 O(n lo...
  • 最长上升子序列

    2021-01-28 22:22:26
    本文将会用几道模板题来试着说明最长上升子序列该如何操作。 最长上升子序列一、最长上升子序列1.题目描述2.分析3.代码实现二、最长上升子序列II1. 题目描述2. 分析3.代码实现(一)4.代码实现(二)三、合唱队形1. ...
  • 前言 ...现在,他们要做的第一步是将两种不同生物的基因序列转换成两个整数序列,并试图确定他们的最大公共上升子序列的长度,例如有A序列为4 3 2 1 7 8 9,B序列为7 8 9 4 3 2 1,其最长公共子序列是4
  • 题目描述: 给定一个长度为N的数列,求数值严格单调递增的子序列的长度最长是多少。...每一个数字都能单独作为一个上升子序列 其长度为1 代码 import java.util.Scanner; public class Main { public
  • SDUT 最长公共子序列问题 给定两个序列 X={x1,x2,…,xm} 和 Y={y1,y2,…,yn},找出X和Y的最长公共子序列。...每组输出一行,表示所求得的最长公共子序列的长度,若不存在公共子序列,则输出0。 Sample...
  • 这是一个最长连续上升子序列的一个翻版,二话不说...输出要求 最长上升子序列的长度。 输入样例 7 1 7 3 5 9 4 8 输出样例 4 先来回温一下最长连续上升子序列,这个就比较新手了,先把数组输入进去,从i=0到i=n...
  • 300. 最长上升子序列

    万次阅读 2020-06-28 12:01:51
    可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。 你算法的时间复杂度应该为 O(n2) 。 进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗? 分析:动态规划适合于求解组合优化问题、方案数等,本题...
  • 【LeetCode】300. 最长上升子序列 给定一个无序的整数数组,找到...可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。 你算法的时间复杂度应该为 O(n2) 。 进阶: 你能将算法的时间复杂度降低到 O(...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,584
精华内容 633
关键字:

最长上升子序列输出序列