经典字符串算法 “最长上升子序列,最大连续子序列和,最长公共子串”

一、问题描述

这是三道典型的字符串dp问题。
最长上升子序列 在一列数中寻找一些数,这些数满足:任意两个数a[i]和a[j],若i

设dp[i]表示以i为结尾的最长递增子序列的长度,则状态转移方程为:dp[i] = max{dp[j]+1}, 1<=j

考虑两个数a[x]和a[y],x


最大连续子序列和在一列数中寻找一些数,这些数满足:任意两个数a[i]和a[j],若i+1=j,必有a[i]需要明确的是状态转移方程中的状态代表的含义。因为contiguous,所以dp[i]代表的应该以i位置元素结尾的连续值,并非最大值。


最长公共子串:两个字符串中的最常公共连续子串。

找 两个字符串的最长公共子串,这个子串要求在原字符串中是连续的。其实这又是一个序贯决策问题,可以用动态规划来求解。我们采用一个二维矩阵来记录中间的结 果。这个二维矩阵怎么构造呢?直接举个例子吧:"bab"和"caba"(当然我们现在一眼就可以看出来最长公共子串是"ba"或"ab")
   b  a  b
c  0  0  0
a  0  1  0
b  1  0  1
a  0  1  0
我们看矩阵的斜对角线最长的那个就能找出最长公共子串。
不过在二维矩阵上找最长的由1组成的斜对角线也是件麻烦费时的事,下面改进:当要在矩阵是填1时让它等于其左上角元素加1。
   b  a  b
c  0  0  0
a  0  1  0
b  1  0  2
a  0  2  0
这样矩阵中的最大元素就是 最长公共子串的长度。

因此我们需要维护一个二维数组,行数为第一个字符串的长度,列数为第二个字符串的长度。为了截取子串,那么我们需要子串的起始和结束索引。借助之前的分析,因为dp里记录的是到某个节点的长度,因此我们可以通过维护一个长度和结束索引来变相的记录子串的起始和结束索引。


二、Java 代码


   /**
     * 最长递增子序列
     *
     * @param nums
     * @return
     */
    public int getLIS(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        int max = 1;
        int[] dp = new int[nums.length];
        for (int i = 0; i < nums.length; i++) {
            dp[i] = 1;
            for (int j = 0; j < i; j++) {
                if (nums[j] < nums[i]) {
                    dp[i] = Math.max(dp[i], dp[j] + 1);
                    max = Math.max(dp[i], max);
                }
            }
        }
        return max;
    }

    /**
     * 最长递增子序列
     *
     * @param nums
     * @return
     */
    public int getLIS2(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        ArrayList dp = new ArrayList<>();
        for (int item : nums) {
            if (dp.size() == 0 || dp.get(dp.size() - 1) < item) {
                dp.add(item);
            } else {
                int i = Collections.binarySearch(dp, item);//insert position
                dp.set(i < 0 ? -i - 1 : i, item);
            }
        }
        return dp.size();
    }

    /**
     * 最大连续子序列和
     *
     * @param nums
     * @return
     */
    public int getMaxSubArray(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        int maxEndingHere = 0;
        int maxSoFar = Integer.MIN_VALUE;
        for (int i = 0; i < nums.length; i++) {
            if (maxEndingHere < 0) {
                maxEndingHere = 0;
            }
            maxEndingHere += nums[i];
            maxSoFar = Math.max(maxSoFar, maxEndingHere);
        }
        return maxSoFar;
    }

    /**
     * 最长公共子串
     *
     * @param a
     * @param b
     * @return
     */
    public String getLCS(String a, String b) {
        if (a == null || b == null || a.length() == 0 || b.length() == 0) {
            return null;
        }
        int[][] dp = new int[a.length()][b.length()];
        int endHere = 0;
        int maxLen = 0;
        for (int i = 0; i < a.length(); i++) {
            for (int j = 0; j < b.length(); j++) {
                if (i == 0 || j == 0) {
                    dp[i][j] = a.charAt(i) == b.charAt(j) ? 1 : 0;
                } else {
                    dp[i][j] = a.charAt(i) == b.charAt(j) ? dp[i - 1][j - 1] + 1
                            : 0;
                }
                if (dp[i][j] > maxLen) {
                    maxLen = dp[i][j];
                    endHere = i;
                }
            }
        }
        return a.substring(endHere - maxLen + 1, endHere + 1);
    }

refer:http://blog.csdn.net/xiaoliucool1314/article/details/50963293#

你可能感兴趣的:(Algorithm)