647. 回文子串
class Solution {
/*
//方法一:中心拓展法【双指针法】
int num = 0;
public int countSubstrings(String s) {
for(int i = 0; i < s.length(); i++){//遍历每个点,以当前点或当前点相邻的下一个点向外扩展遍历
count(s,i, i);//奇数个数的回文是以一个点为中心向外扩展
count(s,i, i+1);//偶数的回文是以两个点为中心向外扩展
}
return num;
}
public void count(String s, int i, int j){
while(i >= 0 && j < s.length() && s.charAt(i--) == s.charAt(j++))
num++;
}
*/
//方法二:动态规划
/*
* dp[i][j]标识i~j序列是否为回文串
* dp[i][j] = dp[i+1][j-1] && s.charAt(i) == s.charAt(j),依赖于dp矩阵中下一行左一列的结果
* 因此从下往上,从左往右进行遍历
* dp耗费的空间比较大
*/
public String longestPalindrome(String s) {
int res = 0, len;
int start = 0 ,maxlen = 0;
if (s == null || (len = s.length()) < 1) return "";
boolean[][] dp = new boolean[len][len];
for(int i = len - 1; i >= 0; i--){
for(int j = i; j < len; j++){
if(s.charAt(i) == s.charAt(j) && (j - i <= 1 || dp[i + 1][j - 1])){
dp[i][j] = true;
if(j - i + 1 > maxlen){
maxlen = j - i + 1;
start = i;
}
}
}
}
return s.substring(start,start + maxlen);
}
}
5. 最长回文子串
class Solution {
/*
//中心扩展法
public String longestPalindrome(String s) {
if(s == null || s.length() == 0) return null;
int maxlen = 0;
int len = 1;
int start = 0;
for(int i =0; i < s.length(); i++){
int left = i - 1;
int right = i + 1;
while(left >= 0 && s.charAt(left) == s.charAt(i)){
--left;
++len;
}
while(right < s.length() && s.charAt(right) == s.charAt(i)){
++right;
++len;
}
while(left >=0 && right < s.length() && s.charAt(right) == s.charAt(left)){
--left;
++right;
len +=2;
}
if(len > maxlen){
start = left + 1;
maxlen = len;
}
len = 1;
}
return s.substring(start,start + maxlen);
}
*/
//动态规划
public String longestPalindrome(String s) {
int res = 0, len;
int start = 0 ,maxlen = 0;
if (s == null || len = s.length() < 1) return "";
boolean[][] dp = new boolean[len][len];
for(int i = len - 1; i >= 0; i--){
for(int j = i; j < len; j++){
if(s.charAt(i) == s.charAt(j)){
if(j - i <= 1){
dp[i][j] = true;
res++;
}else if(dp[i + 1][j - 1]){
res++;
dp[i][j] = true;
}
if(dp[i][j] == true && j - i + 1 > maxlen){
maxlen = j - i + 1;
start = i;
}
}
}
}
return s.substring(start,start + maxlen);
}
}
20. 有效的括号
class Solution {
public boolean isValid(String s) {
LinkedList<Character> stack = new LinkedList<>();
for(char c : s.toCharArray()){
if(c == '(')stack.push(')');
else if(c=='[')stack.push(']');
else if(c=='{')stack.push('}');
else if(stack.isEmpty()||c!=stack.pop())return false;
}
return stack.isEmpty();
}
}
17. 电话号码的字母组合
class Solution {
//回溯法
public List<String> letterCombinations(String digits) {
List<String> combinatons = new ArrayList<String>();
if(digits.length() == 0)
return combinatons;
Map<Character,String> phoneMap = new HashMap<>(){
{
put('2',"abc");
put('3',"def");
put('4',"ghi");
put('5',"jkl");
put('6',"mno");
put('7',"pqrs");
put('8',"tuv");
put('9',"wxyz");
}
};
backtrack(combinatons,phoneMap,digits,0,new StringBuffer());
return combinatons;
}
public void backtrack(List<String> combinatons, Map<Character,String> phoneMap, String digits, int index, StringBuffer combinaton){
if(index == digits.length()) combinatons.add(combinaton.toString());
else{
char digit = digits.charAt(index);
String letters = phoneMap.get(digit);
for(int i =0; i < letters.length(); i++){
combinaton.append(letters.charAt(i));
backtrack(combinatons,phoneMap,digits,index + 1,combinaton);
combinaton.deleteCharAt(index);
}
}
}
}
3. 无重复字符的最长子串
class Solution {
public int lengthOfLongestSubstring(String s) {
HashMap<Character,Integer> map = new HashMap<>();
/**
*max:用于记录最大不重复子串的长度
*left://滑动窗口左指针
*/
int max = 0,pl = 0;
for(int i = 0;i < s.length(); i++){
/**
1、首先,判断当前字符是否包含在map中,如果不包含,将该字符添加到map(字符,字符在数组下标),
此时没有出现重复的字符,左指针不需要变化。此时不重复子串的长度为:i-left+1,与原来的maxLen比较,取最大值;
2、如果当前字符 ch 包含在 map中,此时有2类情况:
1)当前字符包含在当前有效的子段中,如:abca,当我们遍历到第二个a,当前有效最长子段是 abc,我们又遍历到a,
那么此时更新 left 为 map.get(a)+1=1,当前有效子段更新为 bca;
2)当前字符不包含在当前最长有效子段中,如:abba,我们先添加a,b进map,此时left=0,我们再添加b,发现map中包含b,
而且b包含在最长有效子段中,就是1)的情况,我们更新 left=map.get(b)+1=2,此时子段更新为 b,而且map中仍然包含a,map.get(a)=0;
随后,我们遍历到a,发现a包含在map中,且map.get(a)=0,如果我们像1)一样处理,就会发现 left=map.get(a)+1=1,实际上,left此时
应该不变,left始终为2,子段变成 ba才对。
为了处理以上2类情况,我们每次更新left,left=Math.max(left , map.get(ch)+1).
另外,更新left后,不管原来的 s.charAt(i) 是否在最长子段中,我们都要将 s.charAt(i) 的位置更新为当前的i,
因此此时新的 s.charAt(i) 已经进入到 当前最长的子段中!
*/
if(map.containsKey(s.charAt(i))){
pl = Math.max(pl,map.get(s.charAt(i)) + 1);//注意要取最大值,去除的是最后一个重复的那个字母
}
//不管是否更新left,都要更新 s.charAt(i) 的位置!
map.put(s.charAt(i),i);
max = Math.max(max,i - pl + 1);
}
return max;
}
}