系列文章目录
提示:该系列整理子串问题。
一、找到字符串的最长无重复字符子串
给定一个数组 arr,返回 arr 的最长无重复的字串的长度。
示例:1
输入:[2,3,4,5]
输出:4
示例:2
输入:[2,2,3,4]
输出: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]有两个分支
- str1[i] = str2[j] dp[i][j] = dp[i][j] + 1
- 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);
}
}