編寫一個函數,以字符串做爲輸入,反轉該字符串中的元音字母。javascript
示例 1: 輸入: "hello" 輸出: "holle" 前端
示例 2: 輸入: "leetcode" 輸出: "leotcede" java
說明: 元音字母不包含字母"y"。 正則表達式
個人思路是先把字符串中的元音字母找出來,而後翻轉插入一個新的字符串中。
算法
對於給定字符串s,利用正則表達式篩選出元音字母,express
寫出正則表達式api
var reg = /['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U']/
數組
使用上述正則,利用s.match(reg)
去匹配,發現每次只能匹配一個,且',
也會被匹配上瀏覽器
修正: var reg = /aeiou/ig
函數
s.match(reg)
會返回一個匹配結果的數組,示例:
'leetcode'.match(reg) // ['e', 'e', 'o', 'e']
var reg = /[aeiou]/ig
var arr = s.match(reg)
if(!arr) return s; // 結果爲null,則無元音字母
var res = '' // 結果字符串
var index = arr.length - 1 // 元音數組索引,倒序省去reverse操做
while(i < s.length) {
if(reg.test(s[i])) { // 若是是元音字母
res += arr[index] // 替換
index += 1
} else {
res += s[i]
}
i += 1;
}
複製代碼
代碼看上去沒什麼問題,可是在瀏覽器中運行卻怎麼都不成功
如上圖,指望的結果應該是'leotcede'....................
反覆看了一個多小時,最後發現是reg.test()
的問題,這個api有點坑爹,當reg中的檢索是全局檢索時,即加了g修飾符,test()若是連續使用結果會不一樣,舉個栗子:
如上圖所示,沒有全局修飾符和加上全局修飾符時檢索結果徹底不一樣。
經過查閱MDN:
若是正則表達式設置了全局標誌,test()
的執行會改變正則表達式lastIndex
屬性。連續的執行test()
方法,後續的執行將會從 lastIndex 處開始匹配字符串,(一樣改變正則自己的
exec()
lastIndex屬性值
).
原來是lastIndex搞得鬼,由於使用時我都是對單個字符去匹配,因此若是匹配到了的時候,lastIndex就會變爲1,下一個若是出現連續的匹配,就會沒法匹配成功。
咱們在每一次匹配成功時重置lastIndex就行了,即設置reg.lastIndex = 0
因此最終代碼爲:
var reverseVowels = function(s) {
var reg = /[aeiou]/ig
var arr = s.match(reg)
if(!arr) return s;
var res = ''
var index = arr.length - 1
var i = 0
while(i < s.length) {
if(reg.test(s[i])) {
res += arr[index]
reg.lastIndex = 0 // 重置lastIndex
index -= 1
} else {
res += s[i]
}
i += 1;
}
return res;
};複製代碼
但迴歸開頭,這是算法題,我寫出的這個方法並非優質解法,好吧,看了大佬的解法後,能夠用雙指針來解決這個問題。
思路以下:
題目的要求是翻轉字符串中的元音字母,因此咱們只要找出頭尾的元音字母依次交換就行了,根據大佬的思路寫出以下代碼:
var reverseVowels = function(s) {
var reg = /[aeiou]/i
var i = 0
var len = s.length - 1
while(i < len) {
if(reg.test(s[i]) && reg.test(s[len])) { // 首尾都爲元音,交換
[s[i], s[len]] = [s[len], s[i]]
i += 1;
len -= 1;
} else if(!reg.test(s[i])) { // 首不是元音,比較下一位
i += 1;
} else if(!reg.test(s[len])) { // 尾不是元音,比較上一位
len -= 1;
}
}
return s;
};複製代碼
運行的時候發現s並無被改變,???這是爲何,又是一個坑人的問題,明明一切看起來是那麼有道理。。百思不得其解,後來發現問題就出在字符串,字符串一旦初始化是沒法被修改的,而我卻使用了[s[i], s[len]] = [s[len], s[i]]
去試圖修改字符串。舉個栗子:
var str = 'str'
str[0] = 'a'
str // 'str'
str = 'aaa'
str // 'aaa'複製代碼
爲何字符串經過下標沒法修改,而賦值能夠「修改」,上面看起來是賦值修改了字符串,實際上並無被修改,
字符串是基本數據類型, 基本數據類型的值一旦建立,便沒法修改
建立字符串的時候,實際上在棧內開闢了一塊內存空間來存放該字符串值,內存空間大小在初始化時已經固定了,沒法修改。
進行賦值時,實際上開闢了另外一塊內存空間來存放要賦值的新值,將變量指向了這個棧空間。
而原來的字符串值內存會被垃圾回收機制回收,由於沒有變量指向這個字符串了。
總結
本身的基礎仍是太薄弱了啊,看似一道小小的算法題,牽扯出這麼多小的知識點,都是本身不懂了,慢慢加油吧。~~~