2016-09-02 99 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