日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

判断是否字符串重组 Scramble String @LeetCode

發(fā)布時間:2023/12/8 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 判断是否字符串重组 Scramble String @LeetCode 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

思路:

1 遞歸:

簡單的說,就是s1和s2是scramble的話,那么必然存在一個在s1上的長度l1,將s1分成s11和s12兩段,同樣有s21和s22。
那么要么s11和s21是scramble的并且s12和s22是scramble的;
要么s11和s22是scramble的并且s12和s21是scramble的。

如果要能通過OJ,還必須把字符串排序后進行剪枝

http://blog.unieagle.net/2012/10/23/leetcode%E9%A2%98%E7%9B%AE%EF%BC%9Ascramble-string%EF%BC%8C%E4%B8%89%E7%BB%B4%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/


2 DP:

使用了一個三維數(shù)組boolean result[len][len][len],其中第一維為子串的長度,第二維為s1的起始索引,第三維為s2的起始索引。
result[k][i][j]表示s1[i...i+k]是否可以由s2[j...j+k]變化得來。

http://www.blogjava.net/sandy/archive/2013/05/22/399605.html


package Level5;import java.util.Arrays;/*** Scramble String* * Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty substrings recursively.Below is one possible representation of s1 = "great":great/ \gr eat/ \ / \ g r e at/ \a t To scramble the string, we may choose any non-leaf node and swap its two children.For example, if we choose the node "gr" and swap its two children, it produces a scrambled string "rgeat".rgeat/ \rg eat/ \ / \ r g e at/ \a t We say that "rgeat" is a scrambled string of "great".Similarly, if we continue to swap the children of nodes "eat" and "at", it produces a scrambled string "rgtae".rgtae/ \rg tae/ \ / \ r g ta e/ \t a We say that "rgtae" is a scrambled string of "great".Given two strings s1 and s2 of the same length, determine if s2 is a scrambled string of s1.**/ public class S87 {public static void main(String[] args) {String s1 = "abab";String s2 = "bbaa";System.out.println(isScramble(s1, s2));System.out.println(isScrambleDP(s1, s2));}public static boolean isScramble(String s1, String s2) {if(s1.length() != s2.length()){return false;}if(s1.length()==1 && s2.length()==1){return s1.charAt(0) == s2.charAt(0);}// 排序后可以通過char[] s1ch = s1.toCharArray();char[] s2ch = s2.toCharArray();Arrays.sort(s1ch);Arrays.sort(s2ch);if(!new String(s1ch).equals(new String(s2ch))){return false;}for(int i=1; i<s1.length(); i++){ // 至少分出一個字符出來String s11 = s1.substring(0, i);String s12 = s1.substring(i);String s21 = s2.substring(0, i);String s22 = s2.substring(i); // System.out.println(s1 + "-" + s2 + ": "+ s11 + ", " + s12 + ", " + s21 + ", " + s22);// 檢測前半部是否匹配if(isScramble(s11, s21) && isScramble(s12, s22)){return true;}// 前半部不匹配,檢測后半部是否匹配s21 = s2.substring(0, s2.length()-i);s22 = s2.substring(s2.length()-i);if(isScramble(s11, s22) && isScramble(s12, s21)){return true;}}return false;}public static boolean isScrambleDP(String s1, String s2) {int len = s1.length();if(len != s2.length()){return false;}if(len == 0){return true;}char[] c1 = s1.toCharArray();char[] c2 = s2.toCharArray();// canTransform 第一維為子串的長度delta,第二維為s1的起始索引,第三維為s2的起始索引// canTransform[k][i][j]表示s1[i...i+k]是否可以由s2[j...j+k]變化得來。boolean[][][] canT = new boolean[len][len][len]; for(int i=0; i<len; i++){for(int j=0; j<len; j++){ // 如果字符串總長度為1,則取決于唯一的字符是否想到canT[0][i][j] = c1[i] == c2[j];}}for(int k=2; k<=len; k++){ // 子串的長度for(int i=len-k; i>=0; i--){ // s1[i...i+k]for(int j=len-k; j>=0; j--){ // s2[j...j+k]boolean canTransform = false;for(int m=1; m<k; m++){ // 嘗試以m為長度分割子串// canT[k][i][j]canTransform = (canT[m-1][i][j] && canT[k-m-1][i+m][j+m]) || // 前前后后匹配(canT[m-1][i][j+k-m] && canT[k-m-1][i+m][j]); // 前后后前匹配if(canTransform){break;}}canT[k-1][i][j] = canTransform;}}}return canT[len-1][0][0];}}

同樣思路,換一種寫法:

這其實是一道三維動態(tài)規(guī)劃的題目,我們提出維護量res[i][j][n],其中i是s1的起始字符,j是s2的起始字符,而n是當前的字符串長度,res[i][j][len]表示的是以i和j分別為s1和s2起點的長度為len的字符串是不是互為scramble。
有了維護量我們接下來看看遞推式,也就是怎么根據(jù)歷史信息來得到res[i][j][len]。判斷這個是不是滿足,其實我們首先是把當前s1[i...i+len-1]字符串劈一刀分成兩部分,然后分兩種情況:第一種是左邊和s2[j...j+len-1]左邊部分是不是scramble,以及右邊和s2[j...j+len-1]右邊部分是不是scramble;第二種情況是左邊和s2[j...j+len-1]右邊部分是不是scramble,以及右邊和s2[j...j+len-1]左邊部分是不是scramble。如果以上兩種情況有一種成立,說明s1[i...i+len-1]和s2[j...j+len-1]是scramble的。而對于判斷這些左右部分是不是scramble我們是有歷史信息的,因為長度小于n的所有情況我們都在前面求解過了(也就是長度是最外層循環(huán))。
上面說的是劈一刀的情況,對于s1[i...i+len-1]我們有l(wèi)en-1種劈法,在這些劈法中只要有一種成立,那么兩個串就是scramble的。
總結(jié)起來遞推式是res[i][j][len] = || (res[i][j][k]&&res[i+k][j+k][len-k] || res[i][j+len-k][k]&&res[i+k][j][len-k]) 對于所有1<=k<len,也就是對于所有l(wèi)en-1種劈法的結(jié)果求或運算。因為信息都是計算過的,對于每種劈法只需要常量操作即可完成,因此求解遞推式是需要O(len)(因為len-1種劈法)。
如此總時間復雜度因為是三維動態(tài)規(guī)劃,需要三層循環(huán),加上每一步需要線行時間求解遞推式,所以是O(n^4)。雖然已經(jīng)比較高了,但是至少不是指數(shù)量級的,動態(tài)規(guī)劃還是有很大有事的,空間復雜度是O(n^3)。

public class Solution {public boolean isScramble(String s1, String s2) {int len = s1.length();if(len != s2.length()) {return false;}boolean[][][] canScramble = new boolean[len][len][len+1]; // i,j with sublengthfor(int i=0; i<len; i++) {for(int j=0; j<len; j++) {canScramble[i][j][1] = s1.charAt(i) == s2.charAt(j); // substring start from i with length 1, compared with substring start from j with length 1}}for(int sublen=2; sublen<=len; sublen++) {// end_pos = x+(sublen-1) <= len-1, so x <= len-sublenfor(int i=0; i<=len-sublen; i++) {for(int j=0; j<=len-sublen; j++) {for(int p=1; p<sublen; p++) { // split positioncanScramble[i][j][sublen] |= (canScramble[i][j][p] && canScramble[i+p][j+p][sublen-p]) || (canScramble[i][j+sublen-p][p] && canScramble[i+p][j][sublen-p]);}}}}return canScramble[0][0][len];} }

http://blog.csdn.net/linhuanmars/article/details/24506703


總結(jié)

以上是生活随笔為你收集整理的判断是否字符串重组 Scramble String @LeetCode的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。