找到字符串最长无重复子串
题目描述
给定一个数组arr,返回arr的最长无的重复子串的长度(无重复指的是所有数字都不相同)。
输入
[2,2,3,4,3]
输出
3
方法一
滑动窗口
代码实现
import java.util.*;
public class Solution {
/**
* @param arr int整型一维数组 the array
* @return int整型
*/
public int maxLength (int[] arr) {
// write code here
//左边界left
int left = -1;
int res = 0;
//HashMap 存放出现过的数字以及其坐标
HashMap<Integer, Integer> hashmap = new HashMap<>();
//右边界right,往右扩张right++
for(int right = 0;right < arr.length; right++){
//判断右边界该位置的数字是否出现过
//若出现过则将左边界移至该数字上一次出现过的位置
//保证左右边界内数字没有重复
//可能遇到索引比left原来还小的相同数字,加上max判断
if (hashmap.containsKey(arr[right])){
left = Math.max(left, hashmap.get(arr[right]));
}
//更新坐标
hashmap.put(arr[right], right);
res = Math.max(res, right - left);
}
return res;
}
}
HashMap 简单介绍
HashMap 储存数据的方式是 —— 键值对
对于 HashMap<key, value>而言,key 是唯一的,不可以重复的。
所以,以相同的 key 把不同的 value 插入到 Map 中会导致旧元素被覆盖,只留下最后插入的元素。 不过,同一个对象可以作为值插入到 Map 中,只要对应的key不一样。
方法二
双指针+回头遍历
代码实现
public int maxLength (int[] arr) {
int res = 0, tmp = 0;
//right指针往右移动
for(int right = 0; right < arr.length; right++){
int left = right - 1;
//回头扫描,要是没有找到相同的,左指针一直倒退
while(left >= 0 && arr[right] != arr[left])
left--;
//暂时保存子串长度
//若指针距离比上一个字符时拥有的子串长度大,就tmp + 1,否则就设置为指针距离,方便下一步res进行比较
tmp = tmp < right - left ? tmp + 1 : right - left;
res = Math.max(res,tmp);
}
return res;
最长公共子串
题目描述
给定两个字符串str1和str2,返回两个字符串的最长公共子串
输入
str1=“1AB2345CD”,str2=“12345EF”
输出
“2345”
方法
动态规划
代码实现
public String LCS(String str1, String str2){
if(str1.length() == 0 || str2.length() == 0){
return "-1";
}
//起始位置
int start1 = 0;
//偏移量
int max = 0;
int len1 = str1.length();
int len2 = str2.length();
int[][] dp = new int[len1+1][len2+1];
for(int i = 1; i <= len1; i++){
for(int j = 1; j <= len2; j++){
if(str1.charAt(i-1) == str2.charAt(j-1)){
//将当前相等的字符计入 + 1
dp[i][j] = dp[i-1][j-1] + 1;
}else {
dp[i][j] = 0;
}
if(max < dp[i][j]){
//max记录已经拥有的子串长度
max = dp[i][j];
//因为字符串索引是从0开始的,所以 i - max 刚好是起始位置
start1 = i - max;
}
}
}
if(max == 0) return "-1";
return str1.substring(start1, max+start1);
}
最长回文子串
题目描述
对于一个字符串,请设计一个高效算法,计算其中最长回文子串的长度。给定字符串A以及它的长度n,请返回最长回文子串的长度。
输入
'abc1234321ab", 12
输出
7
代码实现
方法
暴力
public class Palindrome {
public int getLongestPalindrome(String A, int n) {
int res = 0;
//暴力解法
for(int i = 0; i < n; i++){
for(int j = i+1; j <= n; j++){
String tmp = A.substring(i,j);
//调用判断是否为回文子串的方法
if(isPalindrome(tmp)){
res = Math.max(res, tmp.length());
}
}
}
return res;
}
public boolean isPalindrome(String s) {
int len = s.length();
for(int i=0; i< len/2; i++){
if(s.charAt(i) != s.charAt(len-1-i))
return false;
}
return true;
}
}
最长的括号子串
题目描述
给出一个仅包含字符(‘和’)的字符串,计算最长的格式正确的括号子串的长度。对于字符串"(()"“来说,最长的格式正确的子串是”()",长度为2.
输入
“)()())”
输出
4
方法一
使用栈
代码实现
public int longestValidParentheses (String s) {
int res = 0;
Stack<Integer> stack = new Stack<>();
stack.push(-1);
for(int i=0; i < s.length(); i++){
if(s.charAt(i) == '('){
stack.push(i);
} else {
stack.pop();
if(stack.empty()) {
stack.push(i);
} else {
res = Math.max(res, i - stack.peek());
}
}
}
return res;
}
方法二
动态规划
代码实现
public int longestValidParentheses (String s) {
int res = 0;
int[] dp = new int[s.length()];
for(int i = 1; i < s.length(); i++){
//只对当前字符是')'进行处理
if(s.charAt(i) == ')'){
//当()时
if(s.charAt(i-1) == '('){
dp[i] = (i >= 2 ? dp[i-2] : 0) + 2;
} else if(i - dp[i-1] > 0 && s.charAt(i - dp[i-1] - 1) == '('){ //当 (())时
dp[i] = dp[i-1] + ((i-dp[i-1]) >= 2 ? dp[i - dp[i-1] - 2] : 0) + 2;
}
res = Math.max(res, dp[i]);
}
}
return res;
}
最长的覆盖子串
题目描述
给出两个字符串S和T,要求在O(n)的时间复杂度内在S中找出最短的包含T中所有字符的子串。
输入
“XDOYEZODEYXNZ”, “XYZ”
输出
“YXNZ”
方法
滑动窗口
代码实现
public String minWindow (String S, String T) {
HashMap<Character, Integer> need, window;
need = new HashMap<Character, Integer>();
window = new HashMap<Character, Integer>();
for(int i=0; i < T.length(); i++){
char c = T.charAt(i);
need.put(c,need.getOrDefault(c,0)+1);
}
int left = 0, right = 0;
//包含目标T的字符数
int valid = 0;
//记录最小覆盖子串的起始索引及长度
int start = 0, len = Integer.MAX_VALUE;
//窗口不断往右移
while(right < S.length()){
char c = S.charAt(right);
//右移窗口
right++;
//进行窗口内数据更新
if(need.containsKey(c)){
window.put(c,window.getOrDefault(c,0)+1);
if(window.get(c) == need.get(c))
valid++;
}
//判断左侧是否进行收缩
while(valid == need.size()){
//更新最小覆盖子串
if(right - left < len){
start = left;
len = right - left;
}
char d = S.charAt(left);
//左移窗口
left++;
//进行窗口内数据更新
if(need.containsKey(d)) {
if(window.get(d) == need.get(d))
valid--;
window.put(d,window.get(d)-1);
}
}
}
return len == Integer.MAX_VALUE ? "" : S.substring(start,start+len);
}