最长子序列问题(时间复杂度O(nlog(n))

问题:10 , 9 , 8 , 1, 2, 5 ,3,最长子序列是 1, 2, 5。最长子序列长度是3。

思路:用一个数组表示当前的最长的子序列,在接下来新增加的元素中,找到这个子序列中某个可以被新的值替换的位置,这个位置要满足被新的值替换后,依然保证数组中保存的是最长的子序列,并且在此基础上可以有更多的值并入这个数组

code:

class Solution {
    public:
        int lengthOfLIS(vector<int>& nums) {
            vector<int> DP;
            DP.push_back(INT_MIN);
            for(int i=0;i<nums.size();i++)
            {
                vector<int>::iterator it=lower_bound(DP.begin(),DP.end(),nums[i]);

                if(it==DP.end())
                {
                    DP.push_back(nums[i]);
                }
                else 
                {
                    if(*it>nums[i])
                    {
                        *it=nums[i];
                    }
                }
            }
            return DP.size()-1;
        }
    };


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
是的,我们可以使用一些高效的算法来将时间复杂度优化到 O(n log n) 以内。 一种常见的方法是使用后缀数组和最长公共前缀 (LCP) 数组。后缀数组是一个数组,其中包含将一个字符串的所有后缀按字典序排列后的索引。LCP 数组是一个数组,其中包含相邻后缀的最长公共前缀的长度。 我们可以首先使用后缀数组对字符串进行排序,然后使用 LCP 数组来计算重复次数。具体来说,我们可以遍历 LCP 数组,并在每个位置上查找前一个后缀和当前后缀的 LCP。如果 LCP 的长度大于当前重复的次数,则将重复次数更新为 LCP 的长度。最后返回重复次数即可。 以下是一个 Java 代码实现: ``` public static int countRepeats(String s) { int n = s.length(); int[] sa = suffixArray(s); int[] lcp = lcpArray(s, sa); int repeats = 0; for (int i = 1; i < n; i++) { int len = lcp[i]; if (len > repeats) { repeats = len; } } return repeats; } private static int[] suffixArray(String s) { int n = s.length(); Integer[] sa = new Integer[n]; int[] rank = new int[n]; for (int i = 0; i < n; i++) { sa[i] = i; rank[i] = s.charAt(i); } for (int k = 1; k < n; k *= 2) { Arrays.sort(sa, Comparator.comparing(i -> rank[i])); int[] tmp = new int[n]; int r = 0; for (int i = 0; i < n; i++) { if (i > 0 && rank[sa[i-1]] == rank[sa[i]] && sa[i-1]+k < n && rank[sa[i-1]+k/2] == rank[sa[i]+k/2]) { tmp[sa[i]] = r; } else { tmp[sa[i]] = ++r; } } rank = tmp; } int[] res = new int[n]; for (int i = 0; i < n; i++) { res[sa[i]] = i; } return res; } private static int[] lcpArray(String s, int[] sa) { int n = s.length(); int[] rank = new int[n]; for (int i = 0; i < n; i++) { rank[sa[i]] = i; } int[] lcp = new int[n]; int h = 0; for (int i = 0; i < n; i++) { if (rank[i] > 0) { int j = sa[rank[i]-1]; while (i+h < n && j+h < n && s.charAt(i+h) == s.charAt(j+h)) { h++; } lcp[rank[i]] = h; if (h > 0) { h--; } } } return lcp; } ``` 该方法首先使用 `suffixArray` 方法计算字符串 s 的后缀数组。然后使用 `lcpArray` 方法计算 s 的 LCP 数组。最后遍历 LCP 数组,计算重复次数。其中 `suffixArray` 和 `lcpArray` 方法都是经典的算法,可以在各种算法书籍或网站上找到详细的说明。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值