Swift 算法实战之路:基本语法与技巧

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
查看查看160 回复回复2 收藏收藏 分享淘帖 转播转播 分享分享 微信
查看: 160|回复: 2
收起左侧

Swift 算法实战之路:基本语法与技巧

[复制链接]
大秘小蜜 发表于 2016-6-21 16:57:31 | 显示全部楼层 |阅读模式
快来登录
获取最新的苹果动态资讯
收藏热门的iOS等技术干货
拷贝下载Swift Demo源代码
本帖最后由 大秘小蜜 于 2016-6-21 17:22 编辑

Swift是苹果新推出的编程语言,也是苹果首个开源语言。相比于原来的Objective-C,Swift要更轻便和灵活。笔者最近使用Swift实践了大量的算法(绝大部分是硅谷各大公司的面试题),将心得体会总结于下。此文并不是纯粹讨论Swift如何实现某一个具体的算法或者数据结构,如冒泡排序、深度优先遍历,或是树和栈,而是总结归纳一些Swift常用的语法和技巧,以便大家在解决面试题中使用。当然要想了解更多Swift知识点或面试题,可以多访问全球最大的Swift开发者社区——敏捷大拇指http://www.Swifthumb.com

Swift 算法实战之路:基本语法与技巧

Swift 算法实战之路:基本语法与技巧 - 敏捷大拇指 - Swift 算法实战之路:基本语法与技巧





1、基本语法

先来看下面一段代码:

[Swift] 纯文本查看 复制代码
func swap(chars:[Character],  p: Int, q: Int) {
  var temp = chars[p]
  chars[p] = chars[q]
  chars[q] = temp
}
// Assume array is a character array and it has enough elements
swap(array, p: 0, q: 1)


上面代码实现了一个非常简单的功能,就是交换一个数组中的两个值。乍一看非常正确,实际上存在以下几个问题。

  • 在第一个参数前应该加上 inout 关键字。因为在Swift中,struct都是按值传递,class是按引用传递;数组和字典都是struct。所以要改变原来的chars数组,在其前部加入inout关键字,表示是按引用传递。
  • p 和 q 之前应该加入下划线。Swift默认函数的第一个参数是局部(local)变量,而后续参数都是外部(external)变量,外部变量必须声明。如果在p和q前加上下划线,则在调用函数时无需声明外部变量,这样调用起来更简便。
  • temp前的var应该改为let。let用于声明常量(constant),var用于声明变量(variable)。swap函数中,temp并未进行修改,所以应当视为常量,用let来声明。


修改过后的代码为:

[Swift] 纯文本查看 复制代码
func swap(inout chars:[Character],  _ p: Int, _ q: Int) {
  let temp = chars[p]
  chars[p] = chars[q]
  chars[q] = temp
}
// Assume array is a character array and it has enough elements
swap(&array, 0, 1)


再来看一段代码:

[Swift] 纯文本查看 复制代码
func toZero(x: Int) -> Int {
  while x > 0 {
    x -= 1
  }
  return x
}


这里在 x -= 1 处会报错。原因是函数中所有的参数是常量(let),是不可以修改的。解决的方法是在函数中写上var x = x,之后就可以对 x 进行修改了。




2、循环

Swift循环分为for和while两种,注意他们的结构跟传统的 Java, C/C++有很大区别,笔者将其总结如下:

[Swift] 纯文本查看 复制代码
// Assume names is an array holds enough Strings
// for loop
for name in names { }
for i in 0 ... names.count - 1 { }
for i in 0 ..< names.count { }
for _ in 0 ..< names.count { }
for name in names.reverse() { }
for i in 0.stride(through: names.count - 1, by 2) { }
for i in 0.stride(to: names.count, by: 2) { }

// while loop
var i = 0
while i < names.count { }
repeat { } while i < names.count


以上代码非常简单。需要说明的有两个,一个是 for _ in 0 ..< names.count { } 。当我们不需要数组中每一个具体的元素值时,我们就可以用下划线来代表序号。

另一个是是 repeat { } while i < names.count 。这个相当于我们熟悉(java)的 do { } while (i < names.length)。

注意,在循环中,i是let变量,是不可以修改的。




3、排序

swift排序效率很高,写法也很简洁。笔者将其总结如下:

[Swift] 纯文本查看 复制代码
// Sort an Int array,ascending
nums.sortInPlace({$0 < $1})

// Sort an Int array without mutating the original one, ascending
var sortedNums = nums.sort({$0 < $1})

// Sort an array with custom-defined objects, ascending
timeIntervals.sortInPlace({$0.startTime < $1.startTime})

// Sort keys in a dictionary according to its value, ascending
let keys = Array(dict.keys)
var sortedKeys = keys.sort() {
  let value0 = dict[$0]
  let value1 = dict[$1]
  return value0 < value1
}





4、活用Guard语句

使用Guard语句可以让逻辑变得非常清楚,尤其是在处理算法问题的时候,请看下面的代码:

[Swift] 纯文本查看 复制代码
// Returns the index of the first occurrence of needle in haystack, 
// or -1 if needle is not part of haystack
func strStr(haystack: String, _ needle: String) -> Int {
  var hChars = [Character](haystack.characters)
  var nChars = [Character](needle.characters)

  if hChars.count < nChars.count {
    return -1
  }
  if hChars.count == 0 {
    return -1
  }

  for i in 0 ... hChars.count - nChars.count {
    if hChars[ i ] == nChars[0] {
      for j in 0 ..< nChars.count {
        if hChars[i + j] != nChars[j] {
          break
        } else {
          if j == nChars.count - 1 {
            return i
          }
        }
      }
    }
  }  
  return -1
}


上面这段代码是求字符串needle在字符串haystack里首次出现的位置。我们发现for循环中的嵌套非常繁琐,但是如果使用Guard语句代码会变得清晰很多:

[Swift] 纯文本查看 复制代码
func strStr(haystack: String, _ needle: String) -> Int {
  var hChars = [Character](haystack.characters)
  var nChars = [Character](needle.characters)

  guard hChars.count >= nChars.count else {
    return -1
  }
  if nChars.count == 0 {
    return 0
  }

  for i in 0 ... hChars.count - nChars.count {
    guard hChars[ i ] == nChars[0] else {
      continue
    }

    for j in 0 ..< nChars.count {
      guard hChars[i + j] == nChars[j] else {
        break
      }
      if j == nChars.count - 1 {
        return i
      }
    }
  }

  return -1
}


Guard语句的好处是判断条件永远是我们希望的条件而不是特殊情况,且成功避免了大量的if嵌套。

另外在上面代码中,为何要将字符串转化成数组进行处理?因为Swift中没有方法能够以O(1)的时间复杂度取得字符串中的字符,我们常用的string.startIndex.advancedBy(n)方法,其时间复杂度为O(n)。所以笔者在这里以空间换时间的方法进行了优化。




5、总结

Swift是一门独特的语言,本文对其基本知识和语法进行了适当归纳,文中提到的都是基本细节。下次我们会讨论更加进阶的内容,请多加关注Swift开发者社区 敏捷大拇指 Swifthumb.com




相关内容

Swift 算法实战之路:基本语法与技巧
Swift 算法实战之路:数组,字符串,集合,与字典
Swift 算法实战之路:链表
Swift 算法实战之路:栈和队列




作者:故胤道长


都看到这里了,就把这篇资料推荐给您的好朋友吧,让他们也感受一下。

回帖是一种美德,也是对楼主发帖的尊重和支持。

*声明:敏捷大拇指是全球最大的Swift开发者社区、苹果粉丝家园、智能移动门户,所载内容仅限于传递更多最新信息,并不意味赞同其观点或证实其描述;内容仅供参考,并非绝对正确的建议。本站不对上述信息的真实性、合法性、完整性做出保证;转载请注明来源并加上本站链接,敏捷大拇指将保留所有法律权益。如有疑问或建议,邮件至marketing@swifthumb.com

*联系:微信公众平台:“swifthumb” / 腾讯微博:@swifthumb / 新浪微博:@swifthumb / 官方QQ一群:343549891(满) / 官方QQ二群:245285613 ,需要报上用户名才会被同意进群,请先注册敏捷大拇指

嗯,不错!期待更多好内容,支持一把:
支持敏捷大拇指,用支付宝支付10.24元 支持敏捷大拇指,用微信支付10.24元

评分

参与人数 1金钱 +10 贡献 +10 专家分 +10 收起 理由
Anewczs + 10 + 10 + 10 32个赞!专家给力!

查看全部评分

瑶池 发表于 2016-6-24 02:08:33 | 显示全部楼层
mark。
cocoaswift 发表于 2016-6-24 13:57:44 | 显示全部楼层
Guard不是取消了么
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

做任务,领红包。
我要发帖

分享扩散

都看到这里了,就把这资料推荐给您的好朋友吧,让他们也感受一下。
您的每一位朋友访问此永久链接后,您都将获得相应的金钱积分奖励
热门推荐

合作伙伴

Swift小苹果

  • 北京治世天下科技有限公司
  • ©2014-2016 敏捷大拇指
  • 京ICP备14029482号
  • Powered by Discuz! X3.1 Licensed
  • swifthumb Wechat Code
  •   
快速回复 返回顶部 返回列表