LeetCode刷题系列(九)Dynamic Programming(2)Longest Subxxxx

  本篇为使用动态规划解决的的求字符串中的一些子串或子序列题的集合。

Longest Increasing Subsequence

  题目为求一个数组最长的上升子序列。我们使用动规来解决该问题,使用一个f[i]存放前i个数的最长上升子序列,如此可将原问题划分为若干个小问题。对于每个位置的i,我们检测它之前的位置如果有比他小的数,我们认为之前的f是可以用上的,这时我们取最大的就好了。代码:

public int longestIncreasingSubsequence(int[] nums) {
    int []f = new int[nums.length];
    int max = 0;
    for (int i = 0; i < nums.length; i++) {
        f[i] = 1;
        for (int j = 0; j < i; j++) {
            if (nums[j] <= nums[i]) {
                f[i] = f[i] > f[j] + 1 ? f[i] : f[j] + 1;
            }
        }
        if (f[i] > max) {
            max = f[i];
        }
    }
    return max;
}

Longest Consecutive Sequence(不使用动规)

  这道题为求数组中最长的连续序列。这道题不使用动规,因为我们不知道连续的序列数出现的位置,同时还可能存在多个序列,不知道要选择哪个一个所以没有办法分解成小的子问题。不过我们可以使用一个HashSet来优化一下,这样确保每个数只搜索一次即可,时间复杂度为O(n)。

public int longestConsecutive(int[] nums) {
    public int longestConsecutive(int[] nums) {
    HashSet<Integer> set = new HashSet<>();
    for (int i = 0; i < nums.length; i++) {
        set.add(nums[i]);
    }

    int longest = 0;
    for (int i = 0; i < nums.length; i++) {
        int down = nums[i] - 1;
        while (set.contains(down)) {
            set.remove(down);
            down--;
        }

        int up = nums[i] + 1;
        while (set.contains(up)) {
            set.remove(up);
            up++;
        }

        longest = Math.max(longest, up - down - 1);
    }

    return longest;
}<Integer> set = new HashSet<>();
    for (int i = 0; i < nums.length; i++) {
        set.add(nums[i]);
    }

    int longest = 0;
    for (int i = 0; i < nums.length; i++) {
        int down = nums[i] - 1;
        while (set.contains(down)) {
            set.remove(down);
            down--;
        }

        int up = nums[i] + 1;
        while (set.contains(up)) {
            set.remove(up);
            up++;
        }

        longest = Math.max(longest, up - down - 1);
    }

    return longest;
}

Longest Common Substring

  题目为求两个字符串的最长公共子串。这道题可以使用动规也可以不使用,由于公共子串是连续,使用递归可能也不起到优化的效果,因此,我们使用最简单的方法,对于第一个字符串的每个位置,我们都使用一个循环来检测子串:

while (i + len < xlen && j + len < ylen && 
        A.charAt(i + len) == B.charAt(j + len))
            len ++;
    if(len > maxlen)
        maxlen = len;
}

Longest Common Subsequence

  题目为求两个字符串的公共子序列。子序列与子串的区别其实在于子序列不是连续的,而子串必须是连续的。这道题就可以使用动规方法了,因为对比两个字符串中的目前存在的子序列就可以将问题分成小块的问题了。使用一个f[i][j]用来保存第一个字符串的前i个字符与第二个字符串的前j个字符的公共子序列长度,然后进行递归:

for(int i = 1; i <= n; i++){
    for(int j = 1; j <= m; j++){
        f[i][j] = Math.max(f[i - 1][j], f[i][j - 1]);
        if(A.charAt(i - 1) == B.charAt(j - 1))
            f[i][j] = f[i - 1][j - 1] + 1;
    }
}

Longest Common Prefix

  题目为若干个个字符串的最长公共子前缀。我们先保存第一个字符串作为子前缀的初始值,然后逐一比较,有可能是逐步缩小子前缀,那么最后留下来的子前缀即为全部字符串的公共子前缀了:

 prefix = strs[0];
    for(int i = 1; i < strs.length; i++) {
        int j = 0;
        while( j < strs[i].length() && j < prefix.length() && strs[i].charAt(j) == prefix.charAt(j)) {
            j++;
        }
        if( j == 0) {
            return "";
        }
        prefix = prefix.substring(0, j);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值