Scramble String -- LeetCode
生活随笔
收集整理的這篇文章主要介紹了
Scramble String -- LeetCode
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
原題鏈接:?http://oj.leetcode.com/problems/scramble-string/?
這道題看起來是比較復雜的,假設用brute force,每次做分割,然后遞歸求解,是一個非多項式的復雜度,一般來說這不是面試官想要的答案。
這事實上是一道三維動態規劃的題目,我們提出維護量res[i][j][n],當中i是s1的起始字符,j是s2的起始字符,而n是當前的字符串長度,res[i][j][len]表示的是以i和j分別為s1和s2起點的長度為len的字符串是不是互為scramble。
有了維護量我們接下來看看遞推式,也就是怎么依據歷史信息來得到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的全部情況我們都在前面求解過了(也就是長度是最外層循環)。
上面說的是劈一刀的情況,對于s1[i...i+len-1]我們有len-1種劈法,在這些劈法中僅僅要有一種成立,那么兩個串就是scramble的。
總結起來遞推式是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,也就是對于全部len-1種劈法的結果求或運算。由于信息都是計算過的,對于每種劈法僅僅須要常量操作就可以完畢,因此求解遞推式是須要O(len)(由于len-1種劈法)。
如此總時間復雜度由于是三維動態規劃,須要三層循環,加上每一步須要線行時間求解遞推式,所以是O(n^4)。盡管已經比較高了,可是至少不是指數量級的,動態規劃還是有非常大有事的,空間復雜度是O(n^3)。代碼例如以下:public boolean isScramble(String s1, String s2) {if(s1==null || s2==null || s1.length()!=s2.length())return false;if(s1.length()==0)return true;boolean[][][] res = new boolean[s1.length()][s2.length()][s1.length()+1];for(int i=0;i<s1.length();i++){for(int j=0;j<s2.length();j++){res[i][j][1] = s1.charAt(i)==s2.charAt(j);}}for(int len=2;len<=s1.length();len++){for(int i=0;i<s1.length()-len+1;i++){for(int j=0;j<s2.length()-len+1;j++){for(int k=1;k<len;k++){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];}}}}return res[0][0][s1.length()]; }個人認為這是LeetCode中最難的動態規劃的題目了,要進行一次三維動態規劃,對于維護量的含義也比較講究。有朋友會討論這個維護量是怎么提出來的,我自己也沒什么絕對的方法,還是熟能生巧,靠“感覺”,做的題目多了就自然來了,這個做高中數學題有點類似哈,輔助線是靠“靈感”的哈。面試中假設遇到就是top難度的了,只是即使如此,僅僅要思路清晰,還是能夠記住的。假設沒做過,個人認為比較難當場想出來,只是算法大牛就另說了,這樣的題非常常常出如今編程比賽中,ACM高手還是不在話下的哈。
這道題看起來是比較復雜的,假設用brute force,每次做分割,然后遞歸求解,是一個非多項式的復雜度,一般來說這不是面試官想要的答案。
這事實上是一道三維動態規劃的題目,我們提出維護量res[i][j][n],當中i是s1的起始字符,j是s2的起始字符,而n是當前的字符串長度,res[i][j][len]表示的是以i和j分別為s1和s2起點的長度為len的字符串是不是互為scramble。
有了維護量我們接下來看看遞推式,也就是怎么依據歷史信息來得到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的全部情況我們都在前面求解過了(也就是長度是最外層循環)。
上面說的是劈一刀的情況,對于s1[i...i+len-1]我們有len-1種劈法,在這些劈法中僅僅要有一種成立,那么兩個串就是scramble的。
總結起來遞推式是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,也就是對于全部len-1種劈法的結果求或運算。由于信息都是計算過的,對于每種劈法僅僅須要常量操作就可以完畢,因此求解遞推式是須要O(len)(由于len-1種劈法)。
如此總時間復雜度由于是三維動態規劃,須要三層循環,加上每一步須要線行時間求解遞推式,所以是O(n^4)。盡管已經比較高了,可是至少不是指數量級的,動態規劃還是有非常大有事的,空間復雜度是O(n^3)。代碼例如以下:public boolean isScramble(String s1, String s2) {if(s1==null || s2==null || s1.length()!=s2.length())return false;if(s1.length()==0)return true;boolean[][][] res = new boolean[s1.length()][s2.length()][s1.length()+1];for(int i=0;i<s1.length();i++){for(int j=0;j<s2.length();j++){res[i][j][1] = s1.charAt(i)==s2.charAt(j);}}for(int len=2;len<=s1.length();len++){for(int i=0;i<s1.length()-len+1;i++){for(int j=0;j<s2.length()-len+1;j++){for(int k=1;k<len;k++){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];}}}}return res[0][0][s1.length()]; }個人認為這是LeetCode中最難的動態規劃的題目了,要進行一次三維動態規劃,對于維護量的含義也比較講究。有朋友會討論這個維護量是怎么提出來的,我自己也沒什么絕對的方法,還是熟能生巧,靠“感覺”,做的題目多了就自然來了,這個做高中數學題有點類似哈,輔助線是靠“靈感”的哈。面試中假設遇到就是top難度的了,只是即使如此,僅僅要思路清晰,還是能夠記住的。假設沒做過,個人認為比較難當場想出來,只是算法大牛就另說了,這樣的題非常常常出如今編程比賽中,ACM高手還是不在話下的哈。
轉載于:https://www.cnblogs.com/mfrbuaa/p/3762262.html
總結
以上是生活随笔為你收集整理的Scramble String -- LeetCode的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [ZZ] 使用rsync来实现快速删除大
- 下一篇: 位,字,字节之间关系及关联知识普及