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

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

  • 旋转字符串

    问题描述:给一个字符串和一个旋转的偏移量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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值