題目:請實現一個函數,把字符串中的每一個空格替換成「%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).app
當咱們把這種思路闡述給面試官後,他不會就此滿意,他將讓咱們尋找更快的方法。在前面的分析中,咱們發現數組中的不少字符都移動了不少次,能不能減小移動的次數呢?咱們換一種思路,把從前向後替換變爲從後向前替換。函數
考慮時間複雜度爲O(n)的解法,搞定Offer就靠它了spa
咱們先遍歷一次字符串,這樣就可以統計出字符串中空格的總數,並能夠計算出替換以後字符串的總長度。每替換一個空格,長度增長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),比第一個思路要快。
實現以下:(個人指針是從前面開始的)
public class Test4 { //將字符串中的空格變成%20 public static String replaceAll(String str){ //計算有多少個空格 int count=0; char[] strArr = str.toCharArray(); for(int i=0;i<strArr.length;i++){ if(strArr[i]==' '){ count++; } } //定義新數組 char[] newArr=new char[strArr.length+count*2]; //遍歷原數組,遇見空格就在新數組中寫入'%''2''0' //第幾個空格 int num=0; for(int i=0,j=0;i<strArr.length;i++){ //定義一個變量來存newArr的索引 if(strArr[i]!=' '){ newArr[j++]=strArr[i]; }else{ newArr[j++]='%'; newArr[j++]='2'; newArr[j++]='0'; } } return new String(newArr); } public static void main(String[] args) { String str = replaceAll("hello world nihao a"); System.out.println(str); } }