5.最长回文子串
给你一个字符串 s,找到 s 中最长的回文子串。
1.暴力破解的方法
class Solution {
// 循环遍历
public String longestPalindrome(String s) {
int max = 0;
String finalStr = s;
for(int i=0;i<s.length();i++){
for(int j=i+1;j<=s.length();j++){
String judge = s.substring(i,j);
if(check(judge)&&(judge.length()>max)){
max = judge.length();
finalStr = judge;
}
}
}
return finalStr;
}
// 校验是否为回文字符串
public boolean check(String str){
// 检查字符串是否为回文字符串
for(int i=0;i<=str.length()/2;i++){
if(str.charAt(i)!=str.charAt(str.length()-i-1)){
return false;
}
}
return true;
}
}
2.动态规划
动态规划方程:
i:表示左边
j:表示右边
dp[i][j] = (s[i]== s[j]) and (j-i<3 or dp[i+1][j-1])
由于dp[i][j]参考它左下方
(1)先升序填列
(2)后升序填行
public class Solution {
public String longestPalindrome(String s) {
// 特殊用例判断
int len = s.length();
if (len < 2) {
return s;
}
int maxLen = 1;
int begin = 0;
// dp[i][j] 表示 s[i, j] 是否是回文串
boolean[][] dp = new boolean[len][len];
char[] charArray = s.toCharArray();
for (int i = 0; i < len; i++) {
dp[i][i] = true;
}
for (int j = 1; j < len; j++) {
for (int i = 0; i < j; i++) {
if (charArray[i] != charArray[j]) {
dp[i][j] = false;
} else {
if (j - i < 3) {
dp[i][j] = true;
} else {
dp[i][j] = dp[i + 1][j - 1];
}
}
// 只要 dp[i][j] == true 成立,就表示子串 s[i..j] 是回文,此时记录回文长度和起始位置
if (dp[i][j] && j - i + 1 > maxLen) {
maxLen = j - i + 1;
begin = i;
}
}
}
return s.substring(begin, begin + maxLen);
}
}
22.括号生成
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
1.原始而又质朴的暴力破解方法
- 通过循环遍历获取所有的括号类型
-只保留符合要求的括号类型
class Solution {
public List<String> generateParenthesis(int n) {
// 获取List数据
List<String> result = new ArrayList<String>();
// 递归生成所有的数据
generateParenthesis(new char[2*n],0,result);
return result;
}
public void generateParenthesis(char[] chars,int n, List<String> result){
if(n==chars.length){
if(check(chars)){
result.add(new String(chars));
}
}else{
// 首先先加左边
chars[n] = '(';
generateParenthesis(chars,n+1,result);
// 接着后加右边
chars[n] = ')';
generateParenthesis(chars,n+1,result);
}
}
// 校验的基础函数
public boolean check(char[] str){
int balance = 0;
for(int i=0;i<str.length;i++){
if(str[i]=='('){
balance++;
}else if(str[i]==')'){
balance--;
}
// 遍历过程中如果存在右括号大于左括号的数据
if(balance<0){
return false;
}
}
// 最终判断是否 有效
return balance==0;
}
}
2.回溯(DFS+剪枝)
class Solution {
List<String> list = new ArrayList<String>();
public List<String> generateParenthesis(int n) {
dfs("",n,n);
return list;
}
public void dfs(String str,int left,int right){
// 首先判断结束条件
if(left==0&&right==0){
list.add(str);
return;
}
// 如果左边存在左括号
if(left>0){
dfs(str+"(",left-1,right);
}
// 如果右边的数量 大于 左边的数量
if(right>left){
dfs(str+")",left,right-1);
}
}
}
‘’’
3.动态规划:
dp[i]表示i组括号的所有有效组合
dp[i] = “(dp[p]的所有有效组合)+【dp[q]的组合】”,其中 1 + p + q = i , p从0遍历到i-1, q则相应从i-1到0
/**
* 动态规划
* 从f(1),f(2),...,f(n-1)构建出f(n)
*
* 分析一个解的构成:必然从左括号开始,而这个开始的左括号必然对应着一个一个右括号,
* 因此,任何一个解可以表示为 (A)B。
* 令f(n) = (A)B 其中A和B是规模更小时问题的合法解,并且A、B可以为空,
* 并且A中括号对数+B中括号对数之和为n-1
*
* 也就是说,可以从f(0),f(1),f(2),...,f(n-1构建出f(n),其中f0 = ""表示空解。
*/
public List<String> generateParenthesisDp(int n) {
List<String>[] dp = new List[n+1];
dp[0] = Arrays.asList("");
for (int p = 1; p <= n; p++) {
dp[p] = new ArrayList<>();
for (int q = 0; q < p; q++) {
for (String a : dp[q]) {
for (String b : dp[p-q-1]) {
dp[p].add("("+a+")"+b);
}
}
}
}
return dp[n];
}
53. 最大子数组和
1.暴力破解的方法
class Solution {
public int maxSubArray(int[] nums) {
// 最大子数组的和
// 先用暴力破解方法
int max = Integer.MIN_VALUE;
for(int i=0;i<=nums.length-1;i++){
for(int j=i;j<nums.length;j++){
int sum =0;
for(int k=i;k<=j;k++){
sum +=nums[k];
}
if(sum>max){
max= sum;
}
}
}
return max;
}
}
2.动态规划的方程
class Solution {
public int maxSubArray(int[] nums) {
int[] dp = new int[nums.length];
dp[0] = nums[0];
for(int i=1;i<nums.length;i++){
if(dp[i-1]>0){
dp[i] = dp[i-1] +nums[i];
}else{
dp[i] = nums[i];
}
}
// 求动态规划中最大的数据
int max = dp[0];
for(int j=1;j<nums.length;j++){
if(dp[j]>max){
max = dp[j];
}
}
return max;
}
}
// 以第i位结尾的数字
// f(n-1)+nums[i] f(n-1)>0
//f(n)
// nums[i] f(n-1)<0
55. 跳跃游戏
1.动态规划
class Solution {
public boolean canJump(int[] nums) {
int n =nums.length;
boolean[] f = new boolean[n];
f[0] = true;
for(int i=1;i<n;i++){
for(int j=0;j<i;j++){
if(f[j]==true&&j+nums[j]>=i){
f[i]=true;
break;
}
}
if(f[i]==false){
return false;
}
}
return true;
}
}在这里插入代码片
2.贪心算法
class Solution {
public boolean canJump(int[] nums) {
int n = nums.length;
int rightmost = 0;
for(int i = 0;i<n;i++){
if(i<=rightmost){
rightmost = Math.max(rightmost,i+nums[i]);
if(rightmost>=n-1){
return true;
}
}
}
return false;
}
}
62. 不同路径
class Solution {
public int uniquePaths(int m, int n) {
// 首先定义动态规划方程
int[][] dp = new int[m][n];
for(int i=0;i<m;i++){
dp[i][0] = 1;
}
for(int j=0;j<n;j++){
dp[0][j] = 1;
}
for(int i=1;i<m;i++){
for(int j=1;j<n;j++){
dp[i][j] = dp[i][j-1] + dp[i-1][j];
}
}
return dp[m-1][n-1];
}
}
// 这道动态规划 是一道 比较简单的题目
//f[0][i]=1
//f[i][0]=1
//f(m)(n) = f(m-1)(n)+f(m)(n-1)
不同路径 II
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
// 定义动态规划方程
int row = obstacleGrid.length;
int col = obstacleGrid[0].length;
int[][] dp = new int[row][col];
boolean firstFlag = true;
if(obstacleGrid[0][0]==1){
dp[0][0] = 0;
firstFlag = false;
}else{
dp[0][0] = 1;
}
boolean flag = firstFlag;
for(int i=1;i<row;i++){
if(flag){
if(obstacleGrid[i][0]==1){
dp[i][0] = 0;
flag = false;
}else{
dp[i][0] = 1;
}
}else{
dp[i][0] = 0;
}
}
flag = firstFlag;
for(int j=1;j<col;j++){
if(flag){
if(obstacleGrid[0][j]==1){
dp[0][j] = 0;
flag = false;
}else{
dp[0][j] = 1;
}
}else{
dp[0][j] = 0;
}
}
for(int i=1;i<row;i++){
for(int j=1;j<col;j++){
if(obstacleGrid[i][j]==1){
dp[i][j] = 0;
}else{
dp[i][j] = dp[i-1][j]+dp[i][j-1];
}
}
}
return dp[row-1][col-1];
}
}
// 大的动态规划方程
// f(m)(n) = f(m)(n-1) + f(m-1)(n)
// 主要是对边界条件的判断,只要出现其中一个1,则后边都为0
64. 最小路径和
class Solution {
public int minPathSum(int[][] grid) {
// 动态规划
int row = grid.length;
int col = grid[0].length;
int[][] dp = new int[row][col];
dp[0][0] = grid[0][0];
// 首先初始化x轴坐标
for(int i=1;i<row;i++){
dp[i][0] = dp[i-1][0] + grid[i][0];
}
// 接着初始化y轴坐标
for(int j=1;j<col;j++){
dp[0][j] = dp[0][j-1] + grid[0][j];
}
// 接着开始正式循环
for(int i=1;i<row;i++){
for(int j=1;j<col;j++){
dp[i][j] = Math.min(dp[i-1][j]+grid[i][j],dp[i][j-1]+grid[i][j]);
}
}
return dp[row-1][col-1];
}
}
// 最小的路径和
// f(m)(n) = Min(f(m-1)(n)+nums[m][n], f(m)(n-1)+nums[m][n]);
96. 不同的二叉搜索树
结题思路:假设n个节点存在二叉排序树的个数是G(n),1为根节点,2为根节点,…,n为根节点,当1为根节点时,其左子树节点个数为0,右子树节点个数为n-1,同理当2为根节点时,其左子树节点个数为1,右子树节点为n-2,所以可得G(n) = G(0)G(n-1)+G(1)(n-2)+…+G(n-1)*G(0)
class Solution {
public int numTrees(int n) {
int[] dp = new int[n+1];
dp[0] = 1;
dp[1] = 1;
for(int i = 2; i < n + 1; i++)
for(int j = 1; j < i + 1; j++)
dp[i] += dp[j-1] * dp[i-j];
return dp[n];
}
}
139. 单词拆分
1.动态规划的方式
class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
Set<String> set = new HashSet<>(wordDict);
boolean[] dp = new boolean[s.length()+1];
// dp[i] 代表 前i位字符 [0]-[i-1]位置
dp[0] = true;
for(int i = 1;i<=s.length();i++){
for(int j=0;j<i;j++){
if(dp[j]&& set.contains(s.substring(j,i))){
dp[i] = true;
break;
}
}
}
return dp[s.length()];
}
// 字符串 动态规划
// int[] dp = new int[s.length-1];
// dp[i]表示前i位[0-s.length-1] 可由单词组成
// dp[i]= dp[j]&&check(s.substring(i,j))
}
152. 乘积最大子数组
class Solution {
public int maxProduct(int[] nums) {
// 首先要用两个数组,最大,最小的
int[] maxDp = new int[nums.length+1];
int[] minDp = new int[nums.length+1];
// 循环记录 以i为尾部,最小的
maxDp[0] = nums[0];
minDp[0] = nums[0];
for(int i=1;i<nums.length;i++){
maxDp[i] = Math.max(maxDp[i-1]*nums[i],Math.max(nums[i],minDp[i-1]*nums[i]));
minDp[i] = Math.min(minDp[i-1]*nums[i],Math.min(nums[i],maxDp[i-1]*nums[i]));
}
int ans = nums[0];
for(int i=1;i<nums.length;i++){
ans = Math.max(ans,maxDp[i]);
}
return ans;
}
}
198 打家劫舍
class Solution {
public int rob(int[] nums) {
// 首先根据
int n = 0;
// 首先判断边界条件
// 长度为1
if(nums.length==1){
return nums[0];
}
// 长度为2
if(nums.length==2){
return Math.max(nums[0],nums[1]);
}
// 长度为3
int[] dp = new int[nums.length];
dp[0] = nums[0];
dp[1] = Math.max(nums[0],nums[1]);
for(int i=2;i<nums.length;i++){
dp[i] = Math.max(dp[i-1],dp[i-2]+nums[i]);
}
return dp[nums.length-1];
}
}
221. 最大正方形
1.暴力破解
暴力法是最简单直观的做法,具体做法如下:
- 遍历矩阵中的每个元素,每次遇到 11,则将该元素作为正方形的左上角;
- 确定正方形的左上角后,根据左上角所在的行和列计算可能的最大正方形的边长(正方形的范围不能超出矩阵的行数和列数),在该边长范围内寻找只包含 11 的最大正方形;
- 每次在下方新增一行以及在右方新增一列,判断新增的行和列是否满足所有元素都是 1。
class Solution {
public int maximalSquare(char[][] matrix) {
int maxSide = 0;
// 首先获取最大的边长
if(matrix==null||matrix.length==0||matrix[0].length==0){
return 0;
}
int row = matrix.length;
int cols = matrix[0].length;
// 循环获取数据
for(int i=0;i<row;i++){
for(int j=0;j<cols;j++){
// 循环获取数据,针对位数为1的就处理
if(matrix[i][j]=='1'){
maxSide = Math.max(1,maxSide);
// 首先寻找最大的数据
boolean flag = true;
int maxBoundary = Math.min(row - i, cols - j);
for(int k=1;k<maxBoundary;k++){
// 首先校验中线的数据
if(matrix[i+k][j+k]=='0'){
break;
}
// 循环获取
for(int m=0;m<k;m++){
if(matrix[i+m][j+k]=='0'|| matrix[i+k][j+m]=='0'){
flag = false;
break;
}
}
if(flag){
maxSide = Math.max(maxSide,k+1);
}else{
break;
}
}
}
}
}
return maxSide*maxSide;
}
}
2.动态规划
class Solution {
// 接着 使用动态规划
public static int maximalSquare(char[][] matrix) {
// 首先第一种情况 判空
int maxSize =0;
if(matrix == null||matrix.length==0||matrix[0].length==0){
return maxSize;
}
// 接着使用动态规划
int row = matrix.length;
int cols = matrix[0].length;
int[][] dp = new int[row][cols];
for(int i=0;i<row;i++){
for(int j=0;j<cols;j++){
if(matrix[i][j]=='1'){
if(i==0||j==0){
dp[i][j] = 1;
}else{
dp[i][j] = Math.min(Math.min(dp[i-1][j],dp[i][j-1]),dp[i-1][j-1])+1;
}
}
maxSize = Math.max(maxSize,dp[i][j]);
}
}
return maxSize*maxSize;
}
}
279. 完全平方数
1.动态规划方程:dp[i] = MIN(dp[i], dp[i - j * j] + 1)
class Solution {
public int numSquares(int n) {
int[] dp = new int[n+1];
for(int i=1;i<=n;i++){
int minSize = Integer.MAX_VALUE;
for(int j=1;j*j<=i;j++){
minSize = Math.min(minSize,dp[i-j*j]);
}
dp[i] = minSize+1;
}
return dp[n];
}
}
/*
dp[i] = MIN(dp[i], dp[i - j * j] + 1)
*/
300. 最长递增子序列
1.动态规划
class Solution {
public int lengthOfLIS(int[] nums) {
int[] dp = new int[nums.length];
dp[0] = 1;
int maxSize = 1;
for(int i=1;i<nums.length;i++){
dp[i] = 1;
for(int j=0;j<i;j++){
if(nums[i]>nums[j]){
dp[i]= Math.max(dp[i],dp[j]+1);
}
}
maxSize= Math.max(maxSize,dp[i]);
}
return maxSize;
}
}
309. 最佳买卖股票时机含冷冻期
给定一个整数数组prices,其中第 prices[i] 表示第 i 天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
- 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
1.动态规划
class Solution {
public int maxProfit(int[] prices) {
if(prices==null||prices.length==0){
return 0;
}
int n = prices.length;
// 定义动态规划方程
int[][] dp = new int[n][3];
dp[0][0] = -prices[0];
for(int i =1;i<prices.length;i++){
// 第i天持有股票
dp[i][0] = Math.max(dp[i-1][0],dp[i-1][2]-prices[i]);
// 第i天不持有股票,在冷冻期
dp[i][1] = dp[i-1][0]+prices[i];
// 第i天不持有股票,不在冷冻期
dp[i][2] = Math.max(dp[i-1][2],dp[i-1][1]);
}
return Math.max(dp[n-1][1],dp[n-1][2]);
}
}
2.动态规划优化版本
class Solution {
public int maxProfit(int[] prices) {
if(prices==null||prices.length==0){
return 0;
}
int f0 = -prices[0];
int f1 = 0;
int f2 = 0;
int n = prices.length;
for(int i=1;i<n;i++){
// f0代表第i天持有股票
int newf0 = Math.max(f0,f2-prices[i]);
// f1代表第i天不持有股票,在冷冻期
int newf1 = f0 + prices[i];
// f2代表第i天不持有股票,不在冷冻期
int newf2 = Math.max(f1,f2);
// 滚动数据一直赋值
f0= newf0;
f1= newf1;
f2= newf2;
}
return Math.max(f1,f2);
}
}
322. 零钱兑换
给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。
你可以认为每种硬币的数量是无限的。
输入:coins = [1, 2, 5], amount = 11
输出:3
解释:11 = 5 + 5 + 1
示例 2:
输入:coins = [2], amount = 3
输出:-1
示例 3:
输入:coins = [1], amount = 0
输出:0
class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount+1];
Arrays.fill(dp,amount+1);
dp[0] = 0;
for(int i=1;i<=amount;i++){
for(int j=0;j<coins.length;j++){
if(i>=coins[j]){
dp[i] = Math.min(dp[i],dp[i-coins[j]]+1);
}
}
}
return dp[amount]==amount+1?-1:dp[amount];
}
}
337. 打家劫舍 III
小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root 。
除了 root 之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果 两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。
给定二叉树的 root 。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额 。
1.暴力破解方法
在解法一和解法二中,我们使用爷爷、两个孩子、4 个孙子来说明问题
首先来定义这个问题的状态
爷爷节点获取到最大的偷取的钱数呢
首先要明确相邻的节点不能偷,也就是爷爷选择偷,儿子就不能偷了,但是孙子可以偷
二叉树只有左右两个孩子,一个爷爷最多 2 个儿子,4 个孙子
根据以上条件,我们可以得出单个节点的钱该怎么算
4 个孙子偷的钱 + 爷爷的钱 VS 两个儿子偷的钱 哪个组合钱多,就当做当前节点能偷的最大钱数。这就是动态规划里面的最优子结构
由于是二叉树,这里可以选择计算所有子节点
4 个孙子投的钱加上爷爷的钱如下
int method1 = root.val + rob(root.left.left) + rob(root.left.right) + rob(root.right.left) + rob(root.right.right)
两个儿子偷的钱如下
int method2 = rob(root.left) + rob(root.right);
挑选一个钱数多的方案则
int result = Math.max(method1, method2);
将上述方案写成代码如下
public int rob(TreeNode root) {
if (root == null) return 0;
int money = root.val;
if (root.left != null) {
money += (rob(root.left.left) + rob(root.left.right));
}
if (root.right != null) {
money += (rob(root.right.left) + rob(root.right.right));
}
return Math.max(money, rob(root.left) + rob(root.right));
}
2.动态规划方法
表示为公式如下
root[0] = Math.max(rob(root.left)[0], rob(root.left)[1]) + Math.max(rob(root.right)[0], rob(root.right)[1])
root[1] = rob(root.left)[0] + rob(root.right)[0] + root.val;
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int rob(TreeNode root) {
int[] result = robInternel(root);
return Math.max(result[0],result[1]);
}
public int[] robInternel(TreeNode root){
int[] result = new int[2];
if(root==null){
return result;
}
int[] left = robInternel(root.left);
int[] right = robInternel(root.right);
// 不偷
result[0] = Math.max(left[0],left[1])+Math.max(right[0],right[1]);
// 偷
result[1] = root.val + left[0] + right[0];
return result;
}
}
416. 分割等和子集
给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
示例 1:
输入:nums = [1,5,11,5]
输出:true
解释:数组可以分割成 [1, 5, 5] 和 [11] 。
示例 2:
输入:nums = [1,2,3,5]
输出:false
解释:数组不能分割成两个元素和相等的子集。
1.动态规划
- 首先判断数组数量小于2,返回false
- 数组的和为奇数,返回false
- 数组最大元素>数组的和除2,返回false
- 如果数组和为偶数,并且从0-i中能找到和为target的则说明可以
class Solution {
public boolean canPartition(int[] nums) {
// 数组数量小于2的话,肯定不行
if(nums.length<2){
return false;
}
int sum =0;
int maxNum = nums[0];
for(int i=0;i<nums.length;i++){
sum += nums[i];
maxNum = Math.max(nums[i],maxNum);
}
// 如果是奇数,则不行
if(sum%2==1){
return false;
}
int n = nums.length;
int target = sum/2;
if(maxNum>target){
return false;
}
boolean[][] dp = new boolean[n][target+1];
// 默认数据赋值
for(int i=0;i<nums.length;i++){
dp[i][0] = true;
}
dp[0][nums[0]] = true;
for(int i=1;i<n;i++){
int num = nums[i];
for(int j=1;j<=target;j++){
if(j>=num){
dp[i][j] = dp[i-1][j]||dp[i-1][j-num];
}else{
dp[i][j] = dp[i-1][j];
}
}
}
return dp[n-1][target];
}
}
2.动态规划优化之后
class Solution {
public boolean canPartition(int[] nums) {
// 数组数量小于2的话,肯定不行
if(nums.length<2){
return false;
}
int sum =0;
int maxNum = nums[0];
for(int i=0;i<nums.length;i++){
sum += nums[i];
maxNum = Math.max(nums[i],maxNum);
}
// 如果是奇数,则不行
if(sum%2==1){
return false;
}
int n = nums.length;
int target = sum/2;
if(maxNum>target){
return false;
}
boolean[] dp = new boolean[target+1];
dp[0] = true;
for(int i=0;i<n;i++){
int num = nums[i];
for(int j=target;j>=num;j--){
dp[j]|=dp[j-nums[i]];
}
}
return dp[target];
}
}
494. 目标和
1.回朔法统计
class Solution {
public int count= 0;
public int findTargetSumWays(int[] nums, int target) {
// 回溯
findTargetSumWayss(nums,target,0,0);
return count;
}
public void findTargetSumWayss(int[] nums, int target,int index,int sum) {
if(index==nums.length){
if(sum==target){
count++;
}
}else{
findTargetSumWayss(nums,target,index+1,sum+nums[index]);
findTargetSumWayss(nums,target,index+1,sum-nums[index]);
}
}
}
2.动态规划(转换为背包问题)
class Solution {
public int findTargetSumWays(int[] nums, int target) {
int sum = 0;
for(int num:nums){
sum+=num;
}
if((target+sum)%2==1){
return 0;
}
if(sum<Math.abs(target)){
return 0;
}
int w = (target+sum)/2;
int[] dp = new int[w+1];
dp[0]=1;
for(int num:nums){
for(int j=w;j>=num;j--){
dp[j] += dp[j-num];
}
}
return dp[w];
}
}
647. 回文子串
1.暴力破解方法
class Solution {
public int countSubstrings(String s) {
int count = 0;
for(int j=1;j<=s.length();j++){
for(int i=0;i<j;i++){
if(checkString(s.substring(i,j))){
count++;
}
}
}
return count;
}
// 首先使用暴力破解
public boolean checkString(String s){
if(s==null||s.length()==0){
return true;
}
char[] chars = s.toCharArray();
for(int i=0;i<=chars.length/2;i++){
if(chars[i]!=chars[chars.length-1-i]){
return false;
}
}
return true;
}
}
2.动态规划
class Solution {
public int countSubstrings(String s) {
if(s==null||s.length()==0){
return 0;
}
int n = s.length();
boolean[][] dp = new boolean[n][n];
int result = 0;
for(int j=0;j<n;j++){
for(int i=0;i<=j;i++){
if(s.charAt(i)==s.charAt(j)){
if(j-i<=1){
result++;
dp[i][j] = true;
}else if(dp[i+1][j-1]){
result++;
dp[i][j] = true;
}
}
}
}
return result;
}
}