[Swift]编码拾遗

➤微信公众号:山青咏芝(shanqingyongzhi)
➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/
➤GitHub地址:https://github.com/strengthen/LeetCode
➤原文地址:https://www.cnblogs.com/strengthen/p/10978800.html 
➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。
➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

1、寻找重复出现奇数次的数字。

给定一个整形数组,其中只有一个数字出现奇数次,其他数字出现偶数次。找出这个数字?

思考:两个相同的整数异或为零,一个整数和0异或为其本身。异或可以使用交换律和结合律。

例:数组[1,1,2,2,2,3,3,3,3]求出现了奇数次的数字。

1^1^2^2^2^3^3^3^3 

=(1^1)^(2^2)^2^(3^3)^(3^3) 

=0^0^2^0^0

=2

Talk is cheap.Show me your code:

1 //测试用例
2 let arr = [1,1,2,2,2,3,3,3,3]
3 //打印
4 print(arr.reduce(0,^))
5 //Print 2

2、不使用额外辅助变量,如何交换两个整型变量x和变量y的值?

思考:异或可以使用交换律和结合律。

1 x = x ^ y  (​1)
2 y = x ^ y  (2)
3 x = x ^ y  (3)

证明:将式1分别代入式2、式3

1 y = x^y = (x^y)^y = x^(y^y) = x^0 = x
2 x = x^y = (x^y)^x = (x^x)^y = 0^y = y

Talk is cheap.Show me your code:

1 func swap(_ x:inout Int,_ y:inout Int)
2 {
3     x = x ^ y
4     y = x ^ y
5     x = x ^ y
6 }

测试:

1 var x:Int = 1
2 var y:Int = 9
3 swap(&x,&y)
4 print(x)
5 //Print 9
6 print(y)
7 //Print 1

3、不使用pow库函数,求m的n次方?

例:求m的7(二进制:111)次方?

可以拆解为:m^7=(m^100)*(m^010)*(m^001)

通过[&1]和[>>1]来逐位读取指数,为1时将该位代表的指数累乘到最终结果中。

Talk is cheap.Show me your code:

 1 func jump(_ n:Int) -> Int
 2 {
 3     if n <= 2 {return n}
 4     var n1:Int = 1
 5     var n2:Int = 2
 6     var sum:Int = 0
 7     for _ in 3...n
 8     {
 9         sum = n1 + n2
10         n1 = n2
11         n2 = sum
12     }
13     return sum
14 }

测试:

1 print(newPow(3,4))
2 //print 81

4、取模运算和取余运算的区别

取余运算和取模运算的步骤相同。

对于整数a、b。计算a%b:

(1)、求商: c = a/b;

(2)、计算模或余数: r = a - c*b.

求模运算和求余运算在第一步不同: 

取余运算在取c的值时,向0方向舍入;

取模运算在计算c的值时,向-∞方向舍入。

%在Swift、C、C++,Java 中称为余运算符,在Python中成为的模运算符。

取余运算:Swift、C、C++,Java 

取模运算:Python

Swift是取余运算。若b负值,忽略b的符号。即:a % b = a % (-b)

[总结]

当a和b符号一致时:

取余运算和取模运算所得结果一致。

当a和b符号不一致时:

取余运算结果和a符号一致。

取模运算结果和b符号一致。

测试:

1 print(6%4)
2 print(-6%4)
3 print(6%(-4))
4 //Print 2
5 //Print -2
6 //Print 2

5、数组下标(计数排序):统计数字、判断字母出现次数。

给定一个整形数组,数组元素的取值范围0~100。

请用O(n)时间复杂度,从小到大打印出来?

思路:把对应的数值作为数组下标,如果这个数出现过,则对应的数组加1。

Talk is cheap.Show me your code: 

 1 func printNum(_ arr:[Int],_ maxNum:Int)
 2 {
 3     var temp:[Int] = [Int](repeating: 0, count: maxNum + 1)
 4     for i in 0..<arr.count
 5     {
 6         temp[arr[i]] += 1
 7     }
 8     for i in 0...maxNum
 9     {
10         for j in 0..<temp[i]
11         {
12             print("\(j):\(i)")
13         }
14     }
15 }

测试:

 1 let arr:[Int] = [100,5,71,89,66,77,89,91,71,95,5,100]
 2 printNum(arr, 100)
 3 /*
 4 0:5
 5 1:5
 6 0:66
 7 0:71
 8 1:71
 9 0:77
10 0:89
11 1:89
12 0:91
13 0:95
14 0:100
15 1:100
16 */

5、递归(n->1)和递推(1->n)

青蛙一次可以跳1级台阶或2级台阶。求该青蛙跳上n级的台阶有多少种跳法?

递归(n->1)法:很多重复计算

1 func jump(_ n:Int) -> Int
2 {
3     if n <= 2 {return n}
4     else
5     {
6         return jump(n - 1)  +  jump(n - 2)
7     }
8 }

测试:

1 print(jump(10))
2 //print 89

备忘录法:巧用数组下标,去除重复计算

当arr[n] = 0时,表示jump(n)未计算,

当arr[n] != 0时,表示jump(n)已计算。

 1 func jump(_ n:Int) -> Int
 2 {
 3     var arr:[Int] = [Int](repeating: 0, count: 1)
 4     if n <= 2 {return n}
 5     else
 6     {
 7         //数组自动扩容
 8         while(n > arr.count - 1)
 9         {
10             arr += [Int](repeating: 0, count: arr.count)
11         }
12         //未计算
13         if arr[n] == 0
14         {
15             arr[n] = jump(n-1) + jump(n-2)
16             return arr[n]
17         }
18         else
19         {
20             //已计算
21             return arr[n]
22         }
23     }
24 }

测试:

1 print(jump(10))
2 //print 89
3 print(jump(11))
4 //print 144

递推(1->n)法:

 1 func jump(_ n:Int) -> Int
 2 {
 3     if n <= 2 {return n}
 4     var n1:Int = 1
 5     var n2:Int = 2
 6     var sum:Int = 0
 7     for _ in 3...n
 8     {
 9         sum = n1 + n2
10         n1 = n2
11         n2 = sum
12     }
13     return sum
14 }

测试:

1 print(jump(10))
2 //print 89
3 print(jump(11))
4 //print 144
5 print(jump(12))
6 //print 233

使用递归时常考虑以下问题:

(1). 是否有重复计算,可使用备忘录法来优化。

(2). 是否可采取递推(1->n)的方法,减少递归的开销。

猜你喜欢

转载自www.cnblogs.com/strengthen/p/10978800.html