2016-09-02 131 views
2

問題是要反轉元音的字符串,就像輸入「hello」一樣,輸出應該是「holle」。反向元音字符串

我搜索到的快速沒有這樣的問題,所以我想發佈這個作爲一個討論。

我寫了下面的代碼,結果證明需要12ms來反轉這個「hello」,任何人都有使用swift特性的更好的解決方案?

class Solution { 
    func reverseVowels(s: String) -> String { 
     if s == "" { return "" } 
     let vowels = ["a","e","i","o","u","A","E","I","O","U"] 
     var sVowels = [Character]() 
     var reversedStr = "" 
     for vChar in s.characters { 
      if vowels.contains(String(vChar)) { 
       sVowels.append(vChar) 
      } 
     } 
     for char in s.characters { 
      if !vowels.contains(String(char)) { 
       reversedStr = reversedStr + String(char) 
      } else if vowels.contains(String(char)) { 
       reversedStr = reversedStr + String(sVowels.removeLast()) 
      } 
     } 

     return reversedStr 
    } 
} 
+0

如果您覺得您的問題已得到滿足,請將答案標記爲已接受。 – Alexander

回答

4

爲了增加vacawama'sanswer解決方案:

斯威夫特,不像其他流行的語言(即C#和Java),並不要求所有的功能應是一個類裏面。 Solution是一個相當隨意的類,不需要存在。在Swift中,你可以將你的函數寫成自己的獨立實體。

但是,還有一種更好的快速方法。你可以把你的函數爲擴展到String,這導致了一些相當不錯的語法:

extension String { 

    static let vowels: Set<Character> = ["a","e","i","o","u","A","E","I","O","U"] 

    func reverseVowels() -> String { 
     if self == "" { return "" } 

     var chars = Array(self.characters) 

     let indices = chars.enumerate().filter{ String.vowels.contains($0.1) }.map{ $0.0 } 

     let count = indices.count 
     for i in 0 ..< count/2 { 
      swap(&chars[indices[i]], &chars[indices[count - i - 1]]) 
     } 

     return String(chars) 
    } 
} 

"A test string".reverseVowels() //you can call your method directly on a string 

我所做的回答其他改進:

  1. vowels現在可以移動是一個String類的靜態成員,因此在每次調用reverseVowels()時都不會重新生成(儘管編譯器可能會優化它)。
  2. vowels現在是Set,而不是Array,以便使用其更快版本的。通過我的測試,這使得1.4x的功能更快。
  3. 切換到功能,不可變的方式生成indices數組。
+0

我喜歡把'元音'設置爲'Set'的想法,但是你的代碼仍然把它當作'Array'。 「索引」的功能版本與大型字符串的版本相比性能如何? – vacawama

+0

非常感謝!這種方法真的很鼓舞人心,我總是忘記使用擴展名,而且我對使用它的時間非常困惑,但無論如何,這是很好的擴展!是的,設置,沒有必要使這些元音有序。非常感謝。 –

+0

@vacawama ** 1)**「但你的代碼仍然將它作爲一個數組」在哪裏? ** 2。**我不確定,我沒有測試過。你願意比較它們嗎? – Alexander

3

你的問題更多的是一個算法問題,而不是一個Swift問題。我對斯威夫特一無所知。

所以這裏是我用Java編寫的算法解決方案。以下是您可以在代碼中使用的要點:

  1. 使用散列表存儲元音。然後您可以在O(1)時間執行查找。我想在你的Swift代碼中,你正在使用一個數組,它可以花費O(n)時間來搜索。
  2. 將輸入字符串轉換爲數組,以便您可以在數組中直接操作(交換)字符,而不是重新構建新字符串。在我的代碼中,我只在最後創建了一個新的字符串。
import java.util.Set; 
import java.util.HashSet; 
import java.util.Arrays; 

public class ReverseVowels { 

    public static String reverseVowels(String s) { 

    // Create a hash table for vowels. 
    Set<Character> vowels = 
     new HashSet<Character>(
      Arrays.asList('a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U')); 
    // Convert input string to array so that we can write into it. 
    char[] result = s.toCharArray(); 

    int i = 0; 
    int j = result.length-1; 
    while (i < j) { 
     if (!vowels.contains(result[i])) { 
      i++; 
     } 
     else if (!vowels.contains(result[j])) { 
      j--; 
     } 
     else { 
      // Both are vowels. 
      char temp = result[i]; 
      result[i] = result[j]; 
      result[j] = temp; 
      i++; 
      j--; 
     } 
    } 
    return new String(result); 
    } 

    public static void main(String argv[]) { 
     System.out.printf("%s\n", reverseVowels("hello")); 
     System.out.printf("%s\n", reverseVowels("qwetupoabt")); 
    } 
} 

輸出:

% java ReverseVowels 
holle 
qwatopuebt 

斯威夫特翻譯:

func reverseVowels(s: String) -> String { 
    // Create a set for vowels. 
    let vowels: Set<Character> = ["a","e","i","o","u","A","E","I","O","U"] 

    // Convert input string to array so that we can write into it. 
    var result = Array(s.characters) 

    var i = 0 
    var j = result.count - 1 
    while i < j { 
     if !vowels.contains(result[i]) { 
      i += 1 
     } 
     else if !vowels.contains(result[j]) { 
      j -= 1 
     } 
     else { 
      // Both are vowels. 
      let temp = result[i] 
      result[i] = result[j] 
      result[j] = temp 
      i += 1 
      j -= 1 
     } 
    } 
    return String(result) 
} 
+0

這正是我如何做到的。嘗試添加答案的快速版本。 –

+1

這是一個很好的算法。我投票並提供了Swift翻譯。 – vacawama

+0

這個算法可以改進。對於像「aexxxxxxxxxxx」這樣的字符串,它會重複檢查第一個字符是否爲元音,直到找到要交換的另一個元音。 – vacawama

3

試試這個:

func reverseVowels(s: String) -> String { 
    if s == "" { return "" } 
    let vowels: Set<Character> = ["a","e","i","o","u","A","E","I","O","U"] 
    var indices = [Int]() 
    var chars = Array(s.characters) 
    for (index, vChar) in chars.enumerate() { 
     if vowels.contains(vChar) { 
      indices.append(index) 
     } 
    } 
    let count = indices.count 
    for i in 0 ..< count/2 { 
     swap(&chars[indices[i]], &chars[indices[count - i - 1]]) 
    } 

    return String(chars) 
} 

算法:

  1. vowelsSet<Character>減少轉換和加快contains(感謝@AlexMomchliov爲Set想法)
  2. 將字符串到[Character]
  3. 找到元音的位置
  4. 交換元音
  5. 重新創建字符串[Character]
+0

很好的答案!我對你的答案進行了一些改進,你可能想查看一下。 – Alexander

1

另一種方式:

1拿起所有的元音和反向他們。

2用反向元音映射原始字符串中的所有元音。

func reverseVowels(s: String) -> String { 
    let vowelSet: Set<Character> = ["a","e","i","o","u","A","E","I","O","U"] 
    var reversedVowelIterator = s.characters.filter{vowelSet.contains($0)}.lazy.reverse().generate() 
    return String(s.characters.map{vowelSet.contains($0) ? reversedVowelIterator.next()! : $0}) 
} 

print(reverseVowels("hello")) //->holle 
print(reverseVowels("Reverse Vowels of a String")) //->Rivarso Vewols ef e Streng