相关字符串letcode算法题

目标字符串动态交叉拼接

题意:
判断目标字符串是不是可以由其他两个字符串动态交叉拼接
示例:
字符串a: aabcc 字符串b: dbbca 目标字符串:aadbbcbcac
目标字符串可以由 字符串a和字符串b交叉拼接

解题思路:
dp[i][j] 表示字符串的前i+j 可以由s1的前i个字符 和s2的前j个字符组成
表达式:
dp[i][j] = dp[i-1][j]&& s1[i-1]=target[i+j-1] || dp[i][j-1] && s2[j-1]=targeti+j-1
表示 前i-1+j个字符可由s1前i-1个字符和s2前j个字符组成,如果目标字符第i+j个字符与s1的第i个字符相等,那么 前i+j个字符可以由s1的前i个字符和s2的前j个字符组成
或者:
前i-1+j个字符可由s1前i个字符和s2前j-1个字符组成,如果目标字符第i+j个字符与s2的第j个字符相等,那么 前i+j个字符可以由s1的前i个字符和s2的前j个字符组成

代码:

 static boolean  sIntervalSubStr(String s1, String s2, String target) {
        if (s1.length() + s2.length() != target.length()) return false;
        int len1 = s1.length();
        int len2 = s2.length();
        int len3 = target.length();

        char[] ch1 = s1.toCharArray();
        char[] ch2 = s2.toCharArray();
        char[] ch3 = target.toCharArray();

        //dp表示记录是否可以组成
        boolean [][] dp = new boolean[len1+1][len2+1];
        //表示都为空的时候肯定可以
        dp[0][0]=true;

        for (int i=1;i<ch1.length;i++){
            dp[i][0]= dp[i-1][0]&& ch1[i-1]==ch3[i-1];
        }
        for (int i=1;i<ch2.length;i++){
            dp[0][i]= dp[0][i-1]&& ch2[i-1]==ch3[i-1];
        }
        for (int i =1;i<=len1;i++){
            for (int j=1;j<=len2;j++){
                dp[i][j] = (dp[i-1][j]&& (ch1[i-1]==ch3[i+j-1])) || (dp[i][j-1] && (ch2[j-1]==ch3[i+j-1]));
            }
        }
        return  dp[len1][len2];
    }
 public static void main(String[] args) {
        System.out.println(sIntervalSubStr("aabcc", "dbbca","aadbbcbcac"));
    }

字符串编辑距离

题意:
字符串的编辑距离表示 一个字符串可以由另外一个字符串 通过最少的编辑次数 变成另外一个字符, 编辑操作包括 将一个字符进行替换 插入一个字符 删除一个字符
示例:
字符串s1=‘a’ 字符串s2=‘b’ 编辑距离为1 即 a替换为b
字符串s1=‘aab’ 字符串s2=‘db’ 编辑距离为2 即 s1删除第一个字符a 将第二个字符a替换为d

解题思路
使用二维数组dp记录最小替换次数 , dp[i][j]表示 字符串s1的前i个字符串转换为s2字符串的前j个字符串的最小编辑距离

when s1[i]==s2[j] 表示s1字符串的第i位置的字符等于s2字符串第j位置的字符, then dp[i][j]= dp[i-1][j-1]

when s1[i]!=s2[j] 表示s1字符串的第i位置的字符不等于s2字符串第j位置的字符, then dp[i][j] = Math.min(Math.min(dp[i-1][j],dp[i][j-1]),dp[i-1][j-1])+1;
s1[i]!=s2[j] 只能进行 删除s1[i] , 替换s1[i]为s2[j], 插入一个s2[j]字符
意思是:
要么s1字符串第i个位置插入s2[j]位置对应的字符 dp[i][j] = dp[i-1][j]+1
要么s2字符串第j个位置插入s1[i]位置对应的字符 dp[i][j] = dp[i][j-1]+1
要么s1字符串第i位置字符被s2 字符串第j位置字符替换 dp[i][j] = dp[i-1][j-1]+1

代码:

   static int editDistance(String s1, String s2) {
        int len1 = s1.length();
        int len2 = s2.length();
        //dp[i][j]表示 第一个字符串前i个字符变成 目标字符的前j个字符需要编辑的次数
        int [][] dp = new int[len1+1][len2+1];
        for (int i=1;i<=len1;i++){
            //表示特殊情况如s2为空串 那么s1转换为s2字符串 字符编辑为删除i个s1字符 编辑距离为i
            dp[i][0]=i;
        }
        for (int j=1;j<=len2;j++){
            //表示特殊情况如s1为空串 那么s1转换为s2字符串 字符编辑为插入i个s2字符 编辑距离为i
            dp[0][j]=j;
        }

        for (int i=1;i<=len1;i++){
            for (int j=1;j<=len2;j++){
                if(s1.charAt(i-1)==s2.charAt(j-1)){
                    dp[i][j]=dp[i-1][j-1];
                }else{
                    dp[i][j] = Math.min(Math.min(dp[i-1][j],dp[i][j-1]), dp[i-1][j-1])+1;
                }
            }
        }
        return dp[len1][len2];
    }

    public static void main(String[] args) {
        System.out.println(editDistance("a", "d"));
        System.out.println(editDistance("aa", "db"));
        System.out.println(editDistance("aab", "db"));
        System.out.println(editDistance("aabcc", "dbbca"));
    }

最长回文子串

题意:
一个字符串的包含的最长回文串 ,如aba, aabbaa这些都是回文串
解题思路
判断一个字符串的最大回文串,使用二维数组dp记录字符串i到j位置的字符是不是回文串,首先二维数字对角线肯定是回文,通过循环遍历
如果字符串s的最左端i和最右端J字符相等 且字符串s的i-1到j-1的子字符串也是回文,那么字符串s是回文串,特殊情况 字符串s的长度不大于2且左右两端字符相等,那么该字符串也是回文如aa
示例
abcbabc 字符串的最大回文串是 cbabc
代码

public class LongerstSubStr {

    /**
     * 动态规划
     * l =r dp[l][r]  =true
     * dp[l][r] = true  满足 dp[l+1][r-1]=true 且s[l]=s[r]
     */
    public String longSubStr(String s) {
        if (s == null || s.length() < 2) {
            return s;
        }
        int strLen = s.length();
        int maxStart = 0;
        int maxEnd = 1;
        int maxLen = 1;

        boolean[][] dp = new boolean[strLen][strLen];
        for (int i = 0; i < strLen; i++) {
            dp[i][i] = true;
        }
        for (int r = 1; r < strLen; r++) {
            for (int l = 0; l < r; l++) {
                if (s.charAt(l) == s.charAt(r) && (r - l <= 2 || dp[l + 1][r - 1])) {
                    dp[l][r] = true;
                    if (r - l + 1 > maxLen) {
                        maxLen = r - l + 1;
                        maxStart = l;
                        maxEnd = r;
                    }
                }
            }
        }
        return s.substring(maxStart, maxEnd + 1);
    }

    public static void main(String[] args) {
        LongerstSubStr subStr = new LongerstSubStr();
        String s = subStr.longSubStr("abcbabc");
        System.out.printf(s);
    }
}

无重复字符的最长字符串

题目描述
字符串s中不包含重复字符的最大子字符串
解题思路
利用滑动窗口的形式 记录不重复字符串的起始位置,已经最长长度
示例
如字符串abdead 的最长字符串 可以是 abde 也可以是bdea 这个根据题意是第一个还是最后一个最长字符串
代码

   public static int maxLengthNoRepeatStrLenth(String s) {
        Map<Character, Integer> map = new HashMap<>();
        //最长长度
        int maxLen = 1;
        int end = 0,start=0;
        for (; end < s.length(); end++) {
            if (map.containsKey(s.charAt(end))) {
                start = Math.max(map.get(s.charAt(end)),start);
            }
            map.put(s.charAt(end), end + 1);
            maxLen = Math.max(maxLen, end - start + 1);
        }
        System.out.println(s.substring(start,start+maxLen));
        return maxLen;
    }

    public static void main(String[] args) {
        System.out.println(maxLengthNoRepeatStrLenth("aabcaabc"));
    }

字符串相加

题意:
给出两个数字字符串,求两个字符串的相加之和并输出,要求不可使用BigDecimal大数计算

代码

    public static String addString(String s1, String s2) {
        int i = s1.length() - 1, j = s2.length() - 1, add = 0;
        StringBuilder builder = new StringBuilder();
        while (i >= 0 || j >= 0 || add != 0) {
            int x = i >= 0 ? s1.charAt(i)-'0' : 0;
            int y = j >= 0 ? s2.charAt(j) -'0': 0;
            int sum = x + y + add;
            builder.append(sum % 10);
            add = sum / 10;
            i--;
            j--;
        }
        return builder.reverse().toString();

    }

    public static void main(String[] args) {
        System.out.println(addString("12345","1234567"));
        System.out.println(new BigDecimal("12345").add(new BigDecimal("1234567")).toString());
    }

字符串相乘

题意:
给出两个数字字符串,求字符串相乘结果,要求不可以使用 BigDecimal

代码:

   public static String multiplyString(String s1, String s2) {
        if(s1.equals("0") || s1.equals("0")){
            return "0";
        }
        int m = s1.length() , n = s2.length() ;
        int [] ans = new int[m+n];
        for (int i =m-1;i>=0;i-- ){
            int x= s1.charAt(i)-'0';
            for (int j=n-1;j>=0;j--){
                int y= s2.charAt(j)-'0';
                ans[i+j+1]+= x*y;
            }
        }
        for (int i = m+n-1;i>0;i--){
            ans[i-1]=ans[i]/10+ans[i-1];
            ans[i]= ans[i]%10;
        }
        int index =ans[0]==0?1:0;
        StringBuilder builder = new StringBuilder();
        while (index<m+n){
            builder.append(ans[index]);
            index++;
        }
        return builder.toString();

    }

    public static void main(String[] args) {
        System.out.println(multiplyString("12345","1234567"));
        System.out.println(new BigDecimal("12345").multiply(new BigDecimal("1234567")).toString());
    }

两个字符串最长子序列长度

题意:
两个字符串s1,s2 ,求字符串s1和字符串s2之间的最大子序列;如s1=“acdef”,s2=“abdefg” 那么"adef"既是s1的子序列也是s2的子序列,所有两者的最大子序列就是"adef"

代码

    /**
     * 最长公共子序列
     * dp二维数组 很明显 dp[0][j] = 0 dp[i][0]=0;
     * 如果si==sj 那么dp[i][j] = dp[i-1][j-1] +1 dp[i-1][j-1]表示s1前i-1个字符和s2前j-1个字符的最长公共子序列的长度
     * 如果si!=sj 那么 dp[i][j] = dp[i][j-],dp[i-1][j]最大值 表示 s1 前i个字符和s2前j-1字符最大公共子序列长度
     * 或者 s1前i-1个字符 s2前j字符 的最大子序列长度
     * @param s1
     * @param s2
     * @return
     */
    public static int LongerCommonSubStr(String s1, String s2) {
        int m =s1.length();
        int n= s2.length();

        int[][] dp = new int[m+1][n+1];

        for (int i=1;i<=m;i++){
            for (int j=1;j<=n;j++){
                if(s1.charAt(i-1) == s2.charAt(j-1)){
                    dp[i][j]=dp[i-1][j-1]+1;
                }else{
                    dp[i][j]= Math.max(dp[i-1][j],dp[i][j-1]);
                }
            }
        }
        return dp[m][n];
    }

    public static void main(String[] args) {
        System.out.println(LongerCommonSubStr("abce","abcde"));
    }

单词拆分

题意:
单词拆分 给出一个字符串s 和字符串列表 wordDict 作为字典 判断字符串s是可以使用wordDict字典组成,如字符串helloworld可以由字符串数组{“hello”,“world”}组成
代码:

    public static  boolean wordBreak(String s, List<String> wordDict) {
        Set<String> wordDictSet = new HashSet(wordDict);
        boolean[] dp = new boolean[s.length() + 1];
        dp[0] = true;
        //dp[i] 表示前i个字符可以由字符数组组成
        for (int i = 1; i <= s.length(); i++) {
            for (int j = 0; j < i; j++) {
                if (dp[j] && wordDictSet.contains(s.substring(j, i))) {
                    dp[i] = true;
                    break;
                }
            }
        }
        return dp[s.length()];
    }

    public static void main(String[] args) {

        String word ="hello world";
        List<String> wordDict=new ArrayList<>(Arrays.asList("hello","world"));
        System.out.println(wordBreak(word,wordDict));

    }

尽可能使字符串相等

题意:
尽可能使字符串相等 给定两个长度相等的字符串 s t 其中 si 转换为ti 的开销记作 |si - ti| maxCost 表示最大允许的开销, 在开销小于maxCost情况下, 要求两个字符串尽可能相等

代码:
双指针

 public static  int equalsSubstring(String s, String t, int maxCost) {
        int n = s.length();
        int[] diff = new int[n];
        for (int i = 0; i < n; i++) {
            diff[i] = Math.abs(s.charAt(i) - t.charAt(i));
        }
        //start end 记录双指针的位置
        int max = 0;
        int start = 0, end = 0;
        //记录 替换前start-end 个字符串的开销
        int sum = 0;

        while (end < n) {
            sum += diff[end];
            while (sum > maxCost) {
                //开销大于最大开销 左指针就需要迁移 表示后面不可以在替换了
                sum -= diff[start];
                start++;
            }
            max = Math.max(max, end - start + 1);
            //右指针继续往后移 知道开销代价大于maxCOst
            end++;
        }
        return max;
    }

    public static void main(String[] args) {
        String s = "adbcd";
        String t = "adzef";
        int maxCost = 10;
        System.out.println(equalsSubstring(s,t,maxCost));

    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员路同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值