算法整理-字符串(LCS,旋转字符串)

来源:互联网 发布:安娜伊思·马田 知乎 编辑:程序博客网 时间:2024/06/04 19:02

字符串是编程中最重要的一类数据结构,能否对字符串进行灵活处理是考察一个求职者最基本的要求,而且字符串在面试中占的比重也很大,接下来就针对字符串相关的算法进行简要的整理和归纳。
字符串相关问题包括最长公共子串、最长公共子序列、字符串逆序等等。

  • 旋转字符串

    问题描述:给一个字符串和一个旋转的偏移量offset,将字符串循环右移offset位。如:”abcdefg” 循环右移 4位之后变为了:”defgabc”
    要求做到O(1)的额外空间耗费,O(n)的时间
    思路:将字符串反转,然后分为前后两部分,分别反转,即可。代码如下

package com.xpn.string;public class RotateString {    /**     * @param args     */    public static void main(String[] args) {        System.out.println(new RotateString().rotateString("abcdefg",4));    }     public String rotateString(String str,int offset){        String reverseString=reverseString(str);        String str1=reverseString(reverseString.substring(0,offset));        String str2=reverseString(reverseString.substring(offset));        return str1+str2;    }     public String reverseString(String str){         StringBuffer sb=new StringBuffer();         for(int i=str.length()-1;i>=0;i--){             sb.append(str.charAt(i));         }         return sb.toString();     }}
  • 最长公共子串

    问题描述:输入两个字符串,求最长公共子串。返回最长公共子串的长度。
    解决思路:动态规划的思想进行解决,找出状态转移方程。

package com.xpn.string;public class LCS {    /**     * @param args     */    public static void main(String[] args) {        System.out.println(new LCS().lcs("abcdef", "cde"));    }    int lcs(String a,String b){        int max=0;//保存最大长度        int m=a.length();        int n=b.length();        int opt[][]=new int[m+1][n+1];        for(int i=1;i<=m;i++){            for(int j=1;j<=n;j++){                if(a.charAt(i-1)==b.charAt(j-1))                    opt[i][j]=opt[i-1][j-1]+1;//状态转移方程                if(opt[i][j]>max){                    max=opt[i][j];//保存最大                }            }        }        return max;    }}

改进之后,打印找到的最大公共子串,代码:

package com.xpn.string;public class LCS {    /**     * @param args     */    public static void main(String[] args) {        System.out.println(new LCS().lcs("abcdef", "cde"));    }    int lcs(String a,String b){        int max=0;//保存最大长度        int m=a.length();        int n=b.length();        int opt[][]=new int[m+1][n+1];        int index=0;//保存找到最大长度,最后一个字符的下标        for(int i=1;i<=m;i++){            for(int j=1;j<=n;j++){                if(a.charAt(i-1)==b.charAt(j-1))                    opt[i][j]=opt[i-1][j-1]+1;//状态转移方程                if(opt[i][j]>max){                    max=opt[i][j];//保存最大                    index=i-1;                }            }        }        StringBuilder sBuilder=new StringBuilder();        int begin=index-max;        while(index>begin){            sBuilder.append(a.charAt(index));            index--;        }        System.err.println(sBuilder.reverse().toString());//需要反转        return max;    }}
  • 最大公共子序列

    与最大公共字符串不同的是,这里要求的序列不一定是连续的。上代码

package com.xpn.string;public class LCS2 {    /**     * @param args     */    public static void main(String[] args) {        System.out.println(new LCS2().lcs2("axxxbxxxcd", "abc"));    }    int lcs2(String a,String b){        int m=a.length();        int n=b.length();        int opt[][]=new int[m+1][n+1];        for(int i=1;i<=m;i++){            for(int j=1;j<=n;j++){                if(a.charAt(i-1)==b.charAt(j-1))                    opt[i][j]=opt[i-1][j-1]+1;                else {                    opt[i][j]=Math.max(opt[i-1][j], opt[i][j-1]);                }            }        }        return opt[m][n];    }}

这里只是简单实现了最长公共子序列的长度,如果要进一步找出对应的字符,则需要做进一步处理。
改进之后,可以找出对应的最长公共子序列,通过标记进行处理。代码如下:

package com.xpn.string;public class LCS2 {    /**     * @param args     */    public static void main(String[] args) {        System.out.println(new LCS2().lcs2("axxxbxxxcd", "abcffd"));    }    int lcs2(String a,String b){        int m=a.length();        int n=b.length();        int opt[][]=new int[m+1][n+1];        char flag[][]=new char[m+1][n+1];        for(int i=1;i<=m;i++){            for(int j=1;j<=n;j++){                if(a.charAt(i-1)==b.charAt(j-1)){                    opt[i][j]=opt[i-1][j-1]+1;                    flag[i][j]='\';                }                else {                    if(opt[i-1][j]>opt[i][j-1]){                        flag[i][j]='|';                    }else {                        flag[i][j]='―';                    }                    opt[i][j]=Math.max(opt[i-1][j], opt[i][j-1]);                }            }        }        StringBuffer sBuffer=new StringBuffer();//保存结果        for(int i=1;i<=m;i++){            System.out.println();            for(int j=1;j<=n;j++){                //System.out.print(flag[i][j]+" ");                if(flag[i][j]=='\'){                    sBuffer.append(b.charAt(j-1));                    break;                }            }        }        System.out.println();        System.out.println(sBuffer.toString());        return opt[m][n];    }}

这里只找出了一个,如果要找出所有的公共子序列,需要通过递归进一步实现。

0 0