字串问题——最长无重复字符子串、最长公共子串

系列文章目录

提示:该系列整理子串问题。



一、找到字符串的最长无重复字符子串

给定一个数组 arr,返回 arr 的最长无重复的字串的长度。

示例:1

输入:[2,3,4,5]
输出:4

示例:2

输入:[2234]
输出:3

1.滑动窗口法:

可以使用一个双指针模拟一个滑动窗口。初始化窗口为 (left, right],所以left从-1开始。窗口不断往右扩大。根据题目的要求,即遇到有重复数字的,在窗口左侧缩小。在每次滑动时,对窗口的大小进行比较,保留最大的长度。

示例:核心代码

   public int maxLength (int[] arr) {
        int res = 0, left = -1;
        //用来存放窗口存放过的数字
        HashMap<Integer, Integer> windows = new HashMap<>();
        //窗口不断往右移
        for(int right = 0; right < arr.length; right++){
            //根据题目,当遇到重复的数字时,缩小左侧窗口
            if( windows.containsKey(arr[right])){
                //因为我们有可能遇到索引比left原来还小的相同数字
                //所以这里要进行比较,目的还是为了缩小左侧窗口,确保窗口内全是不重复的数字
                left = Math.max(left, windows.get(arr[right]));
            }
            //更新窗口内数字的索引
            windows.put(arr[right], right);
            //right-left是窗口大小
            //因为要找最长,所以要进行比较
            res = Math.max(res, right-left);

        }
        return res;
    }

2.双指针+回头遍历

right指针往右移动,回头扫描,要是没有找到相同的,左指针一直倒退,暂时保存子串长度 。若指针距离比上一个字符时拥有的子串长度大,就tmp + 1,否则就设置为指针距离,方便下一步res进行比较。

核心代码:

    public int maxLength (int[] arr) {
        int res = 0, tmp = 0;
        for(int right = 0; right < arr.length; right++){
            int left = right - 1;
            while(left >= 0 && arr[right] != arr[left])
                left--;
            tmp = tmp < right - left ? tmp + 1 : right - left;
            res = Math.max(res,tmp);
        }
        return res;
    }

二、最长公共子串

给定两个字符串 str1,str2,输出两个字符串的最长公共子串,如果最长公共子串为空,输出-1。

示例:1

输入:"1AB2345CD", "12345EF"
输出:"2345"

示例:2

输入:"1AB2345CD", "EF"
输出:"-1"

1.动态规划算法

动态规划算法

  • dp[i][j]有两个分支
  1. str1[i] = str2[j] dp[i][j] = dp[i][j] + 1
  2. str1[i] != str2[j] dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1])
public static String LCS(String str1, String str2) {
   // write code here
   //零界值判断
   if (str1 == null || str2 == null || (str1.isEmpty() && str2.isEmpty())) {
       return "-1";
   }
   int str1L = str1.length();
   int str2L = str2.length();
   int[][] dp = new int[str1L][str2L];
   Map<Integer, String> resultMap = new HashMap<>();
   //初始化索引为0的值 这个是基准值
   for (int i = 0; i < str1L; i++) {
       boolean result = str1.charAt(i) == str2.charAt(0);
       dp[i][0] = result ? 1 : 0;
       resultMap.put(i * str1L, result ? str2.substring(0, 1) : "");
   }
   for (int j = 0; j < str2L; j++) {
       boolean result = str1.charAt(0) == str2.charAt(j);
       dp[0][j] = result ? 1 : 0;
       resultMap.put(j, result ? str1.substring(0, 1) : "");
   }
   //动态规划算法
   for (int i = 1; i < str1L; i++) {
       for (int j = 1; j < str2L; j++) {
           if (str1.charAt(i) == str2.charAt(j)) {
               dp[i][j] = dp[i - 1][j - 1] + 1;
               resultMap.put(i * str1L + j, resultMap.get((i - 1) * str1L + j - 1) + str1.charAt(i));
           } else {
               if (dp[i][j - 1] > dp[i - 1][j]) {
                   dp[i][j] = dp[i][j - 1];
                   resultMap.put(i * str1L + j, resultMap.get(i * str1L + j - 1));
               } else {
                   dp[i][j] = dp[i - 1][j];
                   resultMap.put(i * str1L + j, resultMap.get((i - 1) * str1L + j));
               }
           }
       }
   }
   if(dp[str1L-1][str2L-1] <= 0){
       return "-1"; 
   }else{
       return resultMap.get(str1L * (str1L - 1) + str2L - 1);
   }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值