Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2. For example, Given: s1 = "aabcc", s2 = "dbbca", When s3 = "aadbbcbcac", return true. When s3 = "aadbbbaccc", return false.
輸入數組s1,s2和s3,判斷s3是否是由s1和s2中的元素交替組成的。面試
乍一看這題能夠經過遞歸的方式來求解。咱們能夠同時判斷當前下標s1和s2的元素是否是和s3當前下標的元素相同。若是相同,就進入下一輪遞歸。
代碼以下:數組
public boolean isInterleave(String s1, String s2, String s3) { if(s1.length() + s2.length() != s3.length()) return false; return isInterleave(s1, s2, s3, 0,0,0); } public boolean isInterleave(String s1, String s2, String s3, int pointer1, int pointer2, int pointer3){ if(pointer1==s1.length() && pointer2==s2.length())return pointer3 == s3.length(); if(pointer1<s1.length() && s1.charAt(pointer1)==s3.charAt(pointer3) && isInterleave(s1,s2,s3,pointer1+1, pointer2, pointer3+1)) return true; if(pointer2<s2.length() && s2.charAt(pointer2)==s3.charAt(pointer3) && isInterleave(s1,s2,s3,pointer1, pointer2+1, pointer3+1)) return true; return false; }
這段代碼 不出意外的 超時了
微信
由於這裏有太多的重複調用了。不少的判斷在第一次遞歸的過程當中就能夠知道,數組在走到s1和s2中的某個位置pointer1,pointer2時會進入死衚衕。而走到pointer1和pointer2對應的s3中的pointer3也是肯定的。因此若是咱們能夠利用這部分信息,就能夠省略掉不少重複的判斷。這裏咱們利用boolean[][]
數組記錄判斷狀況。數據結構
public boolean isInterleave2(String s1, String s2, String s3) { if(s1.length() + s2.length() != s3.length()) return false; return isInterleave(s1, s2, s3, 0,0,0, new boolean[s1.length()+1][s2.length()+1]); } public boolean isInterleave(String s1, String s2, String s3, int pointer1, int pointer2, int pointer3, boolean[][] isInvalid){ if(isInvalid[pointer1][pointer2]) return false; if(pointer3 == s3.length())return true; boolean isValid = pointer1<s1.length() && s1.charAt(pointer1)==s3.charAt(pointer3) && isInterleave(s1,s2,s3,pointer1+1,pointer2, pointer3+1, isInvalid) || pointer2<s2.length() && s2.charAt(pointer2)==s3.charAt(pointer3) && isInterleave(s1,s2,s3,pointer1,pointer2+1,pointer3+1,isInvalid); if(!isValid) isInvalid[pointer1][pointer2]=true; return isValid; }
一樣適用boolean[][]
做爲存儲臨時值的數據結構,這裏咱們將其表明的含義改變爲至下標(i,j)時是否能夠和前(i-1,j)或是(i,j-1)上的值鏈接知足s3。
解釋以下:在這裏(i,j)
位置值的含義表明若是採用s2的前i個值和s1的前j個值,是否能夠組成s3前i+j個值。因此判斷(i,j)須要參考(i-1,j)和(i,j-1)位置上的值。若是(i-1,j)成立,也就是說s2的前i-1個值和s1的前j個值能夠組成s3前i+j-1個值,那麼若是s2的第i個值等於s3的第i+j個值,那麼該式子成立。(i,j-1)也是同理的。spa
public boolean isInterleave3(String s1, String s2, String s3){ if ((s1.length()+s2.length())!=s3.length()) return false; boolean[][] matrix = new boolean[s2.length()+1][s1.length()+1]; matrix[0][0] = true; for(int i = 1 ; i<s1.length()+1 ; i++){ matrix[0][i] = matrix[0][i-1] && s1.charAt(i-1)==s3.charAt(i-1); } for(int i = 1 ; i<s2.length()+1 ; i++){ matrix[i][0] = matrix[i-1][0] && s2.charAt(i-1)==s3.charAt(i-1); } for(int i = 1 ; i<matrix.length ; i++){ for(int j = 1 ; j<matrix[0].length ; j++){ matrix[i][j] = (matrix[i-1][j] && s2.charAt(i-1)==s3.charAt(i+j-1)) ||(matrix[i][j-1] && s1.charAt(j-1)==s3.charAt(i+j-1)); } } return matrix[s2.length()][s1.length()]; }
在上一種思路中,咱們能夠看到,其實在每一層的遍歷中只有上一層數據和前一個數據對當前數據有參考價值。因此咱們能夠將boolean[][]的二維數組簡化爲boolean[]一維數組的數據結構
。提升空間的利用率。code
public boolean isInterleave4(String s1, String s2, String s3){ if ((s1.length()+s2.length())!=s3.length()) return false; boolean[] matrix = new boolean[s2.length()+1]; for(int i = 0 ; i<=s1.length() ; i++){ for(int j = 0 ; j<=s2.length() ; j++){ if(i==0&&j==0){ matrix[j] = true; }else if(i==0){ matrix[j] = matrix[j-1] && s2.charAt(j-1)==s3.charAt(j-1); }else if(j==0){ matrix[j] = matrix[j] && s1.charAt(i-1) == s3.charAt(i-1); }else{ matrix[j] = (matrix[j-1] && s2.charAt(j-1)==s3.charAt(i+j-1)) || (matrix[j] && s1.charAt(i-1)==s3.charAt(i+j-1)); } } } return matrix[s2.length()]; }
想要了解更多開發技術,面試教程以及互聯網公司內推,歡迎關注個人微信公衆號!將會不按期的發放福利哦~orm