最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java花式解決'分割回文串 ii'問題詳解

 更新時間:2021年12月22日 09:02:20   作者:富春山居_ZYY  
最學習動態(tài)規(guī)劃思想的路上,遇見了‘分割回文串問題’,如臨大敵啊,題目聽起來蠻簡單,思考起來卻也沒那么容易,本文將為大家詳細介紹幾種解決分割回文串 ii問題的辦法,需要的可以參考一下

前言

最學習動態(tài)規(guī)劃思想的路上,遇見了‘分割回文串問題',如臨大敵啊,題目聽起來蠻簡單,思考起來卻也沒那么容易,比解決問題更頭疼的是如何將解決方法進行優(yōu)化,使得時間空間復雜度盡量的小,經過了反復的掙扎思考,終于總結出來了這一篇 分割回文串 ii 的文章,花式解決該問題,總有一款適合你。

牛客鏈接

題目

給出一個字符串s,分割s使得分割出的每一個子串都是回文串

計算將字符串s分割成回文分割結果的最小切割數(shù)

例如: 給定字符串s=“aab”,

返回1,因為回文分割結果[“aa”,“b”]是切割一次生成的。

思路分析

首先,已知字符串s的長度為len,想要求前l(fā)en個字符串被切割成回文串所需要的最小切割數(shù),就會很自然的想到求前i個字符形成的字符串切割成回文串需要的最小切割數(shù),即為狀態(tài)F(i)。

然后,會想到前i個字符形成的字符串分割變成回文串需要的最大切割數(shù)為i-1。例如字符串"aab",切2刀形成長度為1的回文串"a",“a”,“b”。

再然后,關鍵在于求解最小切割數(shù)的過程,這里采取暴力求解,定義變量j,使之小于i,在我們已知狀態(tài)F(j)的情況下(即前j個字符形成的字符串的最小切割次數(shù)),如果[j+1,i]是回文串,那么再來上一刀就可以求出當前用最少的切割次數(shù)。那么此時F(i)= min(F(i),F(xiàn)(j)+1),意思就是在上一次求得的前i個字符串的分割次數(shù)和這一次求得的次數(shù)進行對比,取最小值。(注:這里的[j+1,i]指的是字符串第j+1個字符到第i個字符的意思,并非字符串下標索引,寫代碼時,轉換成索引就應該是求下標為j-1的字符到下標為i的字符形成的字符串是否為回文串)

緊接著,就該實現(xiàn)判斷是否為回文串的方法,簡單的思想就是,為該方法提供字符串s,提供子串的起始下標start與終點下標end,start<end的條件下,使start向后走,end向前走,但凡對應到字符串s中的字符不一樣,就說明不是回文串,返回false,如果成功遍歷完了循環(huán),說明是回文串,返回true。

最后,將F(len)的值返回。

動歸四角度:

1.狀態(tài)定義F(i):字符串s的前i個字符的最小分割次數(shù);

2.狀態(tài)間的轉移方程定義:F(i)=min(F(i),F(xiàn)(j)+1),0 <= j < i,且F(j)為已知狀態(tài),當[j+1,i]為回文串時,執(zhí)行此狀態(tài)轉移方程

3.狀態(tài)的初始化:F(i) = i-1,注意F(0)為-1;

例如,當字符串為"aa",因為[1,2]為回文串,F(xiàn)(2)= min(F(2),F(xiàn)(0)+1)=min(1,0)= 0,得到正確答案

4.返回結果 :F(s.length());

案例說明

為了方便理解,這里采取了更長的字符串"aabaa",一步步帶你走過程。

初級代碼

import java.util.*;
public class Solution {
    //判斷是否為回文串
    public boolean func(String s,int start,int end) {
        while(start<end) {
            if(s.charAt(start)!=s.charAt(end)) {
                return false;
            }
            start++;
            end--;
        }
        return true;
    }
    public int minCut (String s) {
        int len = s.length();//字符串的長度
        if(len == 0) return 0;//當長度為0時直接返回0
        int[] count = new int[len + 1];//用于記錄狀態(tài)
        //狀態(tài)初始化
        for(int i = 0;i <= len;i ++) {
            count[i] = i-1;
        }
        for(int i = 1;i <= len;i++) {
            for(int j = 0;j <= i-1;j++) {
                if(func(s,j,i-1)) {
                    count[i] = Math.min(count[i],count[j]+1);//狀態(tài)轉移方程
                }
            }
        }
        return count[len];//返回結果
    }
}

在整個進行狀態(tài)計算的過程中,兩層for循環(huán)時間復雜度為O(N2),判斷是否為回文串的方法時間復雜度為O(N),因此總的來說,總的時間復雜度為O(N3)

代碼升級

可以看出來,用上面的代碼時間復雜度還是比較高的,因此代碼還需升級才是

1.回文串動歸

首先,關于回文串的判斷方法,每次判斷是否要進行狀態(tài)轉移方程時都要調用回文串方法,這真的有必要嗎,或許也可以使用動態(tài)規(guī)劃的思想將每種字符子串是否為回文串的狀態(tài)記錄下來。

狀態(tài)四角度:

1.狀態(tài)定義F(i,j):字符區(qū)間[i,j]是否為回文串

2.狀態(tài)間的轉移方程定義F(i,j):

如果i == j,表示單字符,F(xiàn)(i,j) = true;

如果j == i+1,表明倆字符是緊挨著的,如果在總字符串s中對應的字符相同,F(xiàn)(i,j)= true,反之F(i,j) = false;

其他的情況中,F(xiàn)(i,j) = (s.charAt(i) == s.charAt(j)) && F(i+1,j-1);

該轉移方程的意思為字符首尾字符相同,且去掉字符區(qū)間的首位字符后的字符區(qū)間的狀態(tài)F(i+1,j-1)仍然為回文串才證明[i,j]字符串區(qū)間為回文串即F(i,j)= true

3.狀態(tài)的初始化:F(i,j) = false

4.返回結果狀態(tài)二維布爾類型數(shù)組

注:由于在狀態(tài)轉移的過程中,求F(i,j)會只用到之前已經計算過的狀態(tài)F(i+1,j-1),這就意味著i需要從后向前遍歷,使用的是已經更新過結果的值

import java.util.*;
public class Solution {
    //判斷是否為回文串
    public boolean[][] func2 (String s) {
        int len = s.length();//字符串的長度
        boolean[][] ret = new boolean[len][len];
        //記錄狀態(tài)的二維數(shù)組,默認值為false
        //由于i<=j<len,所以ret數(shù)組實際只更新了一半
        for(int i = len;i >= 0;i--) {
            for(int j = i;j<len;j++) {
                if(i == j) {
                    ret[i][j] = true; //單字符比為回文串
                }else if(j == i+1) {
                    if(s.charAt(i) == s.charAt(j)) {
                        ret[i][j] = true; //相鄰字符相同為回文串
                    }else{
                        ret[i][j] = false;//相鄰字符不同就不是回文串
                    }
                }else{
                    ret[i][j] = (s.charAt(i) == s.charAt(j)) && ret[i+1][j-1];
                    //其余轉移情況
                }
            }
        }
        return ret;//返回結果
    }
    public int minCut (String s) {
        int len = s.length();
        if(len == 0) return 0;
        int[] count = new int[len + 1];
        //狀態(tài)初始化
        for(int i = 0;i <= len;i ++) {
            count[i] = i-1;
        }
        boolean[][] ret = func2(s);//調用判斷回文串方法,獲得所有字符子串的是否為回文串的情況
        for(int i = 1;i <= len;i++) {
            for(int j = 0;j <= i-1;j++) {
                //直接在ret數(shù)組中找結果,避免反復調用回文串判斷方法
                if(ret[j][i-1]) {
                    count[i] = Math.min(count[i],count[j]+1);//狀態(tài)轉移方程
                }
            }
        }
        return count[len];//返回結果
    }
}

在該方法中,判斷回文串的方法時間復雜度為O(N2),但因為在主方法中只調用了一次,且回文串判斷方法中只更新了一般的值,因此總的時間復雜度為O(N2)~O(2*N2)

2.綜合動歸

可以看的出來上面的代碼還是比較長的,回文串判斷方法用到了兩層循環(huán),主方法也用到了兩層循環(huán),這不也是優(yōu)化的方向蠻,或許可以把它們放在同一個兩層循環(huán)中。

注:由于回文串判斷方法中的i是一定要從后向前遍歷的,因此主函數(shù)的初識值就需要調整為count[i] = len - i - 1,返回的結果為F(0)

import java.util.*;
public class Solution {
    public int minCut(String s) {
        int len = s.length();//字符串的長度
        if(len == 0) return 0;
        int []count = new int[len+1]; //存放最小分割次數(shù)狀態(tài)的數(shù)組
        boolean [][]p = new boolean[len][len];//存放[i,j]字符區(qū)間是否為回文串的二維數(shù)組
        for(int i = 0; i <= len; i++) count[i] = len - i - 1;//狀態(tài)初始化
        for(int i = len-1;i >= 0;i--){
            for(int j = i;j < len;j++){
                //j-i<2 條件成立且第一個條件成立包含著單個字符串和相鄰字符串的情況
                //p[i+1][j-1] 為 ture 且第一個條件成立則代表著其他的回文串狀態(tài)轉移類型
                //以上情況有一項成立則F(i,j)為 ture
                if(s.charAt(i) == s.charAt(j) && (j-i<2||p[i+1][j-1])){
                    p[i][j] = true;
                    count[i] = Math.min(count[i],count[j+1]+1);//狀態(tài)轉移方程
                }
            }
        }
        return count[0];//返回結果
    }
}

通過這樣的方法,直接將時間復雜度降到了O(N2)

3.奇思妙想

上面幾種方法,需要將回文串的判斷狀態(tài)都記錄下來,且判斷回文串的方法都是從子字符串的兩頭向中間進行判斷,或許有一種方法,可以直接不用記錄下來每種子字符串的是否為回文串的狀態(tài),并且從中間向兩頭進行判斷回文串。

可以設置兩個變量i和j,[i,j]且j==i代表著下標為i的單個字符,必定是回文串,F(xiàn)(j+1)= min(F(j+1),F(xiàn)(i)+1),以此為中心,i--,j++,如果區(qū)間兩頭的字符相同,說明[i-1,j+1]的區(qū)間字符串為回文串,在不超出原字符串s的總區(qū)間[0,len-1]的循環(huán)情況下,重復上面的操作,直到循環(huán)條件不成立

回文串可能是奇數(shù)個字符,也可能是偶數(shù)個字符,上面的情況是奇數(shù)個字符的情況,換成偶數(shù)個字符的情況只需要判斷[i,i+1]是否為回文串,如果是,就參考上面的方式,以此為中心向兩頭展開,求以[i,i+1]為中心最長的回文串,從而求出每個狀態(tài)的最小分割數(shù)。

案例說明:

import java.util.*;
public class Solution {
    public int minCut(String s) {
        int len = s.length();//字符串的長度
        if(len == 0) return 0;
        int[] count = new int[len + 1];
        for(int i = 0; i <= len; i++) count[i] = i - 1;//狀態(tài)初始化
        for(int i = 0; i < len; i++) {
            func3(s, i, i, count);//奇數(shù)個字符的回文串
            func3(s, i, i + 1, count);//偶數(shù)個字符的回文串
        }
        return count[len];//返回結果
    }     
    private  void func3(String s, int i, int j, int[] count) {
        //不超過字符串s的區(qū)間范圍且下標i的字符和下標j的字符相等的條件下向兩頭擴展,得到最長的回文串,以此來求出狀態(tài)
        while(i >= 0 && j < s.length() && s.charAt(i) == s.charAt(j)) {
            count[j + 1] = Math.min(count[j + 1], count[i] + 1); //狀態(tài)轉移
            --i;//左區(qū)間擴展一格
            ++j;//右區(qū)間擴展一格
        }
        return;
    }  
} 

到此這篇關于Java花式解決'分割回文串 ii'問題詳解的文章就介紹到這了,更多相關Java解決分割回文串 ii內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • java中Executor,ExecutorService,ThreadPoolExecutor詳解

    java中Executor,ExecutorService,ThreadPoolExecutor詳解

    這篇文章主要介紹了java中Executor,ExecutorService,ThreadPoolExecutor詳解的相關資料,需要的朋友可以參考下
    2017-02-02
  • Java多線程run方法中直接調用service業(yè)務類應注意的問題及解決

    Java多線程run方法中直接調用service業(yè)務類應注意的問題及解決

    這篇文章主要介紹了Java多線程run方法中直接調用service業(yè)務類應注意的問題及解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • SpringBoot使用Thymeleaf模板引擎訪問靜態(tài)html的過程

    SpringBoot使用Thymeleaf模板引擎訪問靜態(tài)html的過程

    這篇文章主要介紹了SpringBoot使用Thymeleaf模板引擎訪問靜態(tài)html的過程,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-10-10
  • SpringCloud hystrix服務降級概念介紹

    SpringCloud hystrix服務降級概念介紹

    什么是服務降級?當服務器壓力劇增的情況下,根據(jù)實際業(yè)務情況及流量,對一些服務和頁面有策略的不處理或換種簡單的方式處理,從而釋放服務器資源以保證核心交易正常運作或高效運作
    2022-09-09
  • Maven 不同環(huán)境靈活構建的步驟

    Maven 不同環(huán)境靈活構建的步驟

    在項目開發(fā)過程中,合理地使用Maven管理不同的構建環(huán)境(開發(fā)、測試、生產)是提高項目管理效率和應對復雜項目需求的關鍵,本文就來介紹一下Maven 不同環(huán)境靈活構建的步驟,感興趣的可以了解一下
    2024-10-10
  • Spring Boot(二)之web綜合開發(fā)

    Spring Boot(二)之web綜合開發(fā)

    本篇文章為大家介紹spring boot的其它特性(有些未必是spring boot體系桟的功能,但是是spring特別推薦的一些開源技術本文也會介紹),對了這里只是一個大概的介紹,特別詳細的使用我們會在其它的文章中來展開說明
    2017-05-05
  • 在Spring異步調用中傳遞上下文的方法

    在Spring異步調用中傳遞上下文的方法

    這篇文章主要給大家介紹了關于如何在Spring異步調用中傳遞上下文的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Spring具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-08-08
  • SpringBoot之RestTemplate在URL中轉義字符的問題

    SpringBoot之RestTemplate在URL中轉義字符的問題

    這篇文章主要介紹了SpringBoot之RestTemplate在URL中轉義字符的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • Log4j日志記錄框架配置及用法解析

    Log4j日志記錄框架配置及用法解析

    這篇文章主要介紹了Log4j日志記錄框架配置及用法解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-07-07
  • spring boot創(chuàng)建和數(shù)據(jù)庫關聯(lián)模塊詳解

    spring boot創(chuàng)建和數(shù)據(jù)庫關聯(lián)模塊詳解

    這篇文章主要給大家介紹了關于spring boot創(chuàng)建和數(shù)據(jù)庫關聯(lián)模塊的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-10-10

最新評論

黄山市| 禄丰县| 张家界市| 教育| 巩留县| 卢氏县| 通江县| 定结县| 白山市| 都安| 光泽县| 逊克县| 盘锦市| 达日县| 麦盖提县| 阳新县| 濮阳市| 林州市| 扶余县| 沙河市| 裕民县| 余姚市| 南川市| 鄂伦春自治旗| 巨野县| 长春市| 兴宁市| 翼城县| 绍兴县| 黑水县| 措勤县| 阜康市| 鄂州市| 黄平县| 邢台县| 大宁县| 吴桥县| 静乐县| 山阴县| 鄂伦春自治旗| 沙湾县|