最长上升子串问题

===

Index

最长上升子序列

给定一个无序的整数数组,找到其中最长上升子序列的长度。

leetcode 300

int lengthOfLIS(vector<int>& nums) {
    vector<int> res;
    for (int i = 0; i < nums.size(); ++i) {
        auto it = lower_bound(res.begin(), res.end(), nums[i]);
        if (it == res.end()) res.push_back(nums[i]);
        else *it = nums[i];
    }
    return res.size();
}

牛客NC91

输出nums的最长递增子序列(如果有多个答案,输出其中字典序最小的)

vector<int> LCS(vector<int> nums) {
    int n = nums.size();
    vector<int> dp(n), res;
    for (int i = 0; i < n; ++i) {
        auto it = lower_bound(res.begin(), res.end(), nums[i]);
        dp[i] = it - res.begin();
        if (it == res.end()) res.push_back(nums[i]);
        else *it = nums[i];
    }
    for (int i = n - 1; k = res.size() - 1; i >= 0; --i) {
        if (dp[i] == k) res[k--] = nums[i];
    }
    return res;
}

最长连续递增序列

给定一个未经排序的整数数组,找到最长且 连续 的的递增序列,并返回该序列的长度。

leetcode 674

int findLengthOfLCIS(vector<int>& nums) {
    int n = nums.size(), ans = 1;
    if (n <= 1) return n;
    vector<int> dp(n + 1, 1);
    for (int i = 2; i <= n; ++i) {
        if (nums[i - 1] > nums[i - 2]) {
            dp[i] = dp[i - 1] + 1;
        } else dp[i] = 1;
    }
    return *max_element(dp.begin(), dp.end());
}

最长连续序列

给定一个未排序的整数数组,找出最长连续序列的长度。要求算法的时间复杂度为 O(n)。

leetcode 128

输入: [100, 4, 200, 1, 3, 2]
输出: 4
解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。
int longestConsecutive(vector<int>& num) {
    unordered_set<int> s(num.begin(), num.end()), searched;
    int longest = 0;
    for (int i: num) {
        if (searched.find(i) != searched.end()) continue;
        searched.insert(i);
        int j = i - 1, k = i + 1;
        while (s.find(j) != s.end()) searched.insert(j--);
        while (s.find(k) != s.end()) searched.insert(k++);
        longest = max(longest, k - 1 - j);
    }
    return longest; 
}

最长递增子序列的个数

给定一个未排序的整数数组,找到最长递增子序列的个数。

leetcode 673

int findNumberOfLIS(vector<int>& nums) {
    int maxlen = 1, ret = 0;
    vector<int> cnt(nums.size(), 1), dp(nums.size(), 1);
    for (int i = 1; i < nums.size(); ++i) {
        for (int j = 0; j < i; ++j) {
            if (nums[i] > nums[j]) {
                if (dp[j] + 1 > dp[i]) dp[i] = dp[j]+1, cnt[i] = cnt[j];
                else if (dp[i] == dp[j] + 1) cnt[i] += cnt[j];
            }
        }
        maxlen = max(maxlen, dp[i]);
    }
    for (int i=0;i < dp.size();++i) 
        if (dp[i] == maxlen) ret += cnt[i];
    return ret;
}

最大上升子序列和

给定一个数的序列,求上升子序列中的最大和,例如序列 (100, 1, 2, 3),最大上升子序列和为100。 noi 3532

int maxLISsum(int a[], int n) { // index begin from 1
    int s[n + 1] = {0}, ans = 0;
    for (int i = 1; i <= n; ++i) {
        s[i] = a[i];
        for (int j = 1; j < i; ++j) {
            if (a[i] > a[j] && s[i] < s[j] + a[i]) 
                s[i] = s[j] + a[i]; 
        }
        ans = max(ans, s[i]);
    }
    return ans;
}

最长公共子上升序列

给定两个整数序列, 求它们的最长上升公共子序列。 noi 2000

f(i1,i2)表示a1a2[0..i2],以a1[i1]结尾的最长上升公共子序列 若a2[i2] == a1[i1],
f(i1,i2) = max{ f(i,i2-1) } + 1 (0<=i<i1)
a2[i2] < a1[i1], f(i1,i2)不变 若a2[i2] > a1[i1], f(i1,i2)不变, max{ f(i,i2) } 的值更新

struct node{
    int len;
    vector<int> iv;
    node(){len = 0;}
} ans[maxn], cur; 

vector<int> maxLCSLIS(int a1[], int n1, int a2[], int n2) {
    for (int i = 0; i < n2; ++i) {
        cur.len = 0; cur.iv.clear();
        for (int j = 0; j < n1; ++j) {
            if (a2[i] > a1[j] && ans[j].len > cur.len) cur = ans[j];
            if (a2[i] == a1[j]) {
                ans[j] = cur; ans[j].len++;
                ans[j].iv.push_back(a1[j]);
            }
        }
    }
    int idx = 0;
    for (int i = 1; i < n1; ++i) {
        if (ans[idx].len < ans[i].len) idx = i;
    }
    return ans[idx].iv;
}

双向最长上升子序列

codechef

给定一个字符串s,仅含小写字母,找出最长的子序列t,满足:可以将t划分成两个字符串t1,t2,使得t1单调不减,t2单调不升,求最长子序列t的长度。

  • 1 <= s.size() <= 2000

分析

定义 dp[k][c1][c2] 表示前k个字符组成的非递减子序列的结尾为字符c1,非递增子序列的结尾为字符c2 所能获得的最长子序列。 时间复杂度 26*26*n

int lws(string &s) {
    int n = s.size(); 
    vector f(26, vector<int>(26));
    for (int i = 0; i < n; ++i) {
        int t = s[i] - 'a';
        auto g = f;
        for (int x = 0; x < 26; ++x) {
            for (int y = 0; y < 26; ++y) {
                if (x <= t) g[t][y] = max(g[t][y], f[x][y] + 1);
                if (y >= t) g[x][t] = max(g[x][t], f[x][y] + 1);
            }
        }
        g.swap(f);
    }
    int ans = 0;
    for (int i = 0; i < 26; ++i) {
        for (int j = 0; j < 26; ++j) 
            ans = max(ans, f[i][j]);
    }
    return ans;
}

打赏一下

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦