前言
广告: 最近github上新开了一个仓库May-Nodes,包括但不限于之前面试遇到的相关数据库,计算机操作系统,Java基础知识,计算机网络以及LeetCode等算法题解等知识。届时也会整理学习使用的PDF文档与资源。有需要的小伙伴 可以点个关注和
star。在持续更新中,总会遇到你想要的。
回文串: 回文串”是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串(解释来源于百度百科)。对于系列的回文串相关的算法涉及到有动态规划,中心扩散法,以及递归回溯等等,可以用来考量的知识点也是比较多的,以下文章将从LeetCode的每日一题入手,来具体总结相关的几个题目:
计数二进制子串
使用位扩展的解法:
private int count = 0;
public int countBinarySubstrings(String s) {
for(int i = 1; i < s.length(); i++) {
if(s.charAt(i-1)!= s.charAt(i))
BinarySubstring(s,i-1,i);
}
return count;
}
public void BinarySubstring(String s, int start, int end) {
char f = s.charAt(start);
char e = s.charAt(end);
while(start >= 0 && end < s.length() && s.charAt(start) == f && s.charAt(end) == e) {
start--;
end++;
count++;
}
}
回文子串
暴力求解
public int countSubstrings(String s) {
int count = 0;
for(int i = 0;i<s.length();i++){
for(int j= i;j<s.length();j++){
if(getCount(s.substring(i,j+1)))
count++;
}
}
return count;
}
private static boolean getCount(String s){
int i= 0;
int j= s.length()-1;
while(i<=j){
if(s.charAt(i)!=s.charAt(j))
{
return false;
}
i++;
j--;
}
return true;
}
使用动态规划
首先明白,这个dp[i][j] 的含义,表示对于 字符串进行从i到j长度的字符串是不是回文串:
- 如果两个字符相等的时候,转移方程
dp[i][j] =dp[i+1][j-1]; - 进行特判: 表示两个是相邻且相等时候 。
- 进行值的求加。
public int countSubstrings(String s) {
if(s == null || s.equals("")){
return 0;
}
int len = s.length();
int result = len;
boolean [][] dp = new boolean[len+1][len+1];
for(int i = 0; i < len; i++){
dp[i][i] = true;
// 首先明白这个动态规划的dp数组是什么意思
}
/**
根据不同的情况进行初值的设置 明白为什么不直接使用到
for(int i= 0;i<len-1;i++) 会出现值的未定义变复制的情况。
**/
for(int i = len - 1;i>= 0 ;i--){
for(int j = i+ 1;j<len; j++){
if(s.charAt(i) ==s.charAt(j)){
if(j- i == 1)
dp[i][j] = true;
else
dp[i][j] =dp[i+1][j-1];
if(dp[i][j])
result++;
}
}
}
return result;
}
使用中心扩散方法
public int countSubstrings(String s) {
// 中心扩展法
int ans = 0;
for (int center = 0; center < 2 * s.length() - 1; center++) {
// left和right指针和中心点的关系是?
// 首先是left,有一个很明显的2倍关系的存在,其次是right,可能和left指向同一个(偶数时),也可能往后移动一个(奇数)
// 大致的关系出来了,可以选择带两个特殊例子进去看看是否满足。
int left = center / 2;
int right = left + center % 2;
while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
ans++;
left--;
right++;
}
}
return ans;
}
最长回文子串
动态规划
大体思想一致还是一致,进行必要的标记标记值。
public String longestPalindrome(String s) {
int start = 0;
int maxlen = 1;
int len =s.length();
if(len<2)
return s;
boolean [][] dp = new boolean[len+1][len+1];
for(int i= 0 ;i<s.length();i++){
dp[i][i] = true;
}
for(int i =len-1;i>=0 ;i--){
for(int j= 1+i;j<len;j++ ){
if(s.charAt(i)== s.charAt(j)){
if(j-i<3){
dp[i][j] = true;
}
else
dp[i][j] =dp[i+1][j-1];
}
else
dp[i][j] = false;
if(dp[i][j] && j-i+1>maxlen){
maxlen= j-i+1;
start = i;
}
}
}
return s.substring(start,maxlen+start);
}
中心扩散
public String longestPalindrome(String s) {
// ababa 求最长公共子串
int len = s.length();
String result = "";
for (int i = 0; i < len * 2 - 1; i++) {
int left = i / 2;
int right = left + i % 2;
while (left >= 0 && right < len && s.charAt(left) == s.charAt(right)) {
String tmp = s.substring(left, right + 1);
if (tmp.length() > result.length()) {
result = tmp;
}
left--;
right++;
}
}
return result;
}
回文串的切割
利用到回溯与递归
public List<List<String>> partition(String s) {
List<List<String>> lists = new ArrayList<>();
List<String> list = new ArrayList<>();
palindrome(s,list,lists);
return lists;
}
private static void palindrome(String s,List<String> list,List<List<String>> lists)
{
if(s.length()==0)
{
lists.add(new ArrayList<>(list));
return;
}
int len = s.length();
for(int i = 0;i<=len;i++){
String p = s.substring(0,i);
if(ishuiwen(p)){
list.add(p);
palindrome(s.substring(i,len),list,lists);
list.remove(list.size()-1);
}
}
}
/**
* 判断是否回文的小函数
* @param args
*/
private static boolean ishuiwen(String s){
if(s.length()==0)
return false;
int left =0;
int right = s.length()-1;
while(left< right){
if(s.charAt(left)!= s.charAt(right))
return false;
left++;
right --;
}
return true;
}
回文串切割-II
利用到动态规划的思想(重要)
public int minCut(String s) {
int len= s.length();
int [] dp = new int[len+1];
for(int i =0;i<len;i++){
dp[i]=i;
}
for(int i= 1;i<s.length();i++){
if(ishuiwen(s,0,i))
{
dp[i] =0;
}
for(int j= 0;j<i;j++){
if(ishuiwen(s,j+1,i))
dp[i] =Math.min(dp[i],dp[j]+1);
}
}
return dp[len-1];
}
private static boolean ishuiwen(String s,int left,int right){
while(left< right){
if(s.charAt(left)!= s.charAt(right))
return false;
left++;
right --;
}
return true;
}