Java 算法之最长子串、最长公共子序列、最长公共子串、最长回文串
1. 无重复字符的最长子串(对应力扣题3)
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
可以使用「滑动窗口」来解决这个问题:
- 我们使用两个指针表示字符串中的某个子串(或窗口)的左右边界,其中左指针代表着窗口的左边界「枚举子串的起始位置」,而右指针代表窗口的右边界
在每一步的操作中,我们会将左指针向右移动一格,表示我们开始枚举下一个字符作为起始位置,然后我们可以不断地向右移动右指针,但需要保证这两个指针对应的子串中没有重复的字符。在移动结束后,这个子串就对应着以左指针开始的,不包含重复字符的最长子串。我们记录下这个子串的长度;
在枚举结束后,我们找到的最长的子串的长度即为答案。 - 判断重复字符:
在上面的流程中,我们还需要使用一种数据结构来判断 是否有重复的字符,常用的数据结构为哈希集合(即 Java 中的 HashSet)。在左指针向右移动的时候,我们从哈希集合中移除一个字符,在右指针向右移动的时候,我们往哈希集合中添加一个字符。
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/solution/wu-zhong-fu-zi-fu-de-zui-chang-zi-chuan-by-leetc-2/
来源:力扣(LeetCode)
//最长无重复字符子串
public static int longestNoRepeatSubstring(String str){
int len = str.length();
Set<Character> set = new HashSet<>();
int slidePtr = 0;
int maxLen = 0;
for(int i = 0; i < len; i++){
while(slidePtr < len && !set.contains(str.charAt(slidePtr))){
set.add(str.charAt(slidePtr));
slidePtr++;
}
maxLen = Math.max(maxLen, slidePtr-i);
set.remove(str.charAt(i));
}
return maxLen;
}
2. 最长公共子序列
给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
- 例如,“ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列。
两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。 - 示例 1:
输入:text1 = "abcde", text2 = "ace"
输出:3
解释:最长公共子序列是 "ace" ,它的长度为 3 。
解题思路
求两个数组或者字符串的最长公共子序列问题,肯定是要用 动态规划
首先,区分两个概念:子序列可以是不连续的;子数组(子字符串)需要是连续的;
另外,动态规划也是有套路的:单个数组或者字符串要用动态规划时,可以把动态规划 dp[i]
定义为 nums[0:i]
中想要求的结果;当两个数组或者字符串要用动态规划时,可以把动态规划定义成两维的 dp[i][j]
,其含义是在 A[0:i]
与 B[0:j]
之间匹配得到的想要的结果。
-
状态定义
比如对于本题而言,可以定义dp[i][j]
表示text1[0:i-1]
和text2[0:j-1]
的最长公共子序列。 (注:text1[0:i-1]
表示的是 text1 的 第 0 个元素到第 i-1 个元素,两端都包含)
之所以dp[i][j]
的定义不是text1[0:i]
和text2[0:j]
,是为了方便当 i = 0 或者 j = 0 的时候,dp[i
][j]表示的为空字符串和另外一个字符串的匹配,这样dp[i][j]
可以初始化为 0. -
状态转移方程
知道状态定义之后,我们开始写状态转移方程。
当 text1[i - 1] == text2[j - 1]
时,说明两个子字符串的最后一位相等,所以最长公共子序列又增加了 1,所以 dp[i][j] = dp[i - 1][j - 1] + 1
;举个例子,比如对于 ac 和 bc 而言,他们的最长公共子序列的长度等于 a 和 b 的最长公共子序列长度 0 + 1 = 1。
当 text1[i - 1] != text2[j - 1]
时,说明两个子字符串的最后一位不相等,那么此时的状态 dp[i][j]
应该是 dp[i - 1][j]
和 dp[i][j - 1]
的最大值。举个例子,比如对于 ace 和 bc 而言,他们的最长公共子序列的长度等于 ① ace 和 b 的最长公共子序列长度0 与 ② ac 和 bc 的最长公共子序列长度1 的最大值,=1。
综上状态转移方程为:
d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + 1 , 当 t e x t 1 [ i − 1 ] = = t e x t 2 [ j − 1 ] ; dp[i][j] = dp[i - 1][j - 1] + 1, 当 text1[i - 1] == text2[j - 1]; dp[i][j]=dp[i−1][j−1]+1,当text1[i−