題目:請實現一個函數,把字串中的每個空格替換成“%20”。例如輸入“We are happy",則輸出”We%20are%20happy".
原因:在網路編程中,如果URL參數中含有特殊字元,如:空格、“#”等,可能導致伺服器端無法獲得正確的參數值。我們需要將這些特殊符號轉換成伺服器識別的字元。轉換規則是在“%”後面跟上ASCII碼的兩位十六進位的表。比如:空格的ASCII瑪是32,即十六進位的0x20,因此空格被替換成“%20”。
時間複雜度為O(n2)不足以拿到Offer
現在我們考慮怎麼做替換操作。最直觀的做法是從頭到尾掃描字串,每一次碰到空白字元的時候做替換。由於是把1個字元替換稱3個字元,我們必須把空格後面的所有的字元都後移兩個位元組,否則就有兩個字元被覆蓋了。
舉個例子,我們從頭到尾把“We are happy"中的每一個空格替換成”%20“。為了形象期間,我們可以用一個表格來表示字串,表格中的每個格子表示一個字元。如下圖所示:
我們替換了第一個空格,這個字串編程圖b中的內容,表格中灰色背景表示需要移動的字元。接著我們替換第二個空格,替換之後的內容如圖c所示。同時我們注意到用深灰色的北京標註”happy“部分被移動了兩次。
假設字元的長度是n。對每個空白字元,需要移動後面O(n)個字元,因此對含有O(n)個空白字元串而言總的時間效率是O(n2).
當我們把這種思路闡述給面試官後,他不會就此滿意,他將讓我們尋找更快的方法。在前面的分析中,我們發現數組中的很多字元都移動了很多次,能不能減少移動的次數呢。我們換一種思路,把從前向後替換成從後向前替換。
考慮時間複雜度為O(n)的解法,搞定Offer就靠它了
我們先遍曆一次字串,這樣就能夠統計出字串中空格的綜述,並可以計算出替換之後字串的總的長度。每替換一個空格,長度增加2,因此替換以後的字串的長度等於原來的長度加上2乘以空格的數目,我們還是以前面的字串”We are happy"為例,“We are happy"這個字串的長度是14,裡面有兩個空格,因此替換之後的字串的長度為18
我們從字串的後面開始複製和替換。首先準備兩個指標,P1和P2. P1指向原始字串的末尾,而P2指向替換之後的字串的末尾。接下來我們向前移動指標P1,逐個把它指向的字元複製到P2指向的位置,直到碰到第一個空格為止。此時字串包含如下圖b所示,灰色陰影的地區是做了字元拷貝的地區。碰到第一個空格之後,把P1向前移動一格,在P2之前插入字串”%20“,由於”%20“的長度為3,同時也要把P2向前移動3格如圖所示。
我們接著向前複製,直到碰到第二個空格(d)所示。和上一次一樣,我們再把P1向前移動1格,並把P2向前移動3格插入”%20“(如圖e),此時P1,P2指向同一個位置,表明所有的空格都已經替換完畢。
從上面的分析我們可以看出,所有的字元都只複製一次,因此這個演算法的時間效率是O(n),比第一個思路要快。
實現如下:
package my_java;public class Test{//計算字串中包含的空格個數public static int getBlankNum(String testString){int count = 0 ;for(int i = 0;i<testString.length();i++){String tempString = String.valueOf(testString.charAt(i));if(tempString.equals(" ")){count++;}}return count;}//列印char[] 數組public static void printArray(char[] testArray){for(char i :testArray){System.out.print(i);}System.out.println();}//將字串空格轉化為20%public static void replaceAllBlank(String testString){if(testString == null || testString.length() <= 0){return;}//字元數組初始長度int length = testString.length();//字元數組增加長度後int newLength = testString.length()+ getBlankNum(testString)*2;char[] tempArray = new char[newLength];System.arraycopy(testString.toCharArray(), 0, tempArray, 0, testString.toCharArray().length);int indexofOriginal = length - 1;int indexofNew = newLength -1;System.out.println("未替換空格時的字串:");printArray(testString.toCharArray());while(indexofOriginal >=0 && indexofOriginal != indexofNew){if(tempArray[indexofOriginal]==' '){tempArray[indexofNew--]='0';tempArray[indexofNew--]='2';tempArray[indexofNew--]='%';}else{tempArray[indexofNew--]= tempArray[indexofOriginal];}indexofOriginal--;}System.out.println("替換空格後的字串:");printArray(tempArray);}public static void main(String[] args){String str = "We are happy";replaceAllBlank(str);}}