TalkGo 算法之美第一期
目录
本文介绍 TalkGo 算法之美第一期题解
一、前言
题目一
输入一个递增排序的数组和一个数字 S,在数组中查找两个数,使得他们的和正好是 S,如果有多对数字的和等于 S,输出两个数的乘积最小的。
题目二
一个有序数组,从随即一位截断,把前段放在后边,如 4 5 6 7 1 2 3 求中位数
二、解析
2.1 题目一
思考:
- 因为递增,负数和正数的情况一致,一组数据最小的值越小则乘积也越小
- 如果出现重复数字,也和正常情况一样的处理
2.1.1 处理方式
- 暴力法
1func TwoSum2For(sum int, array []int) []int {
2 b, arr := checkArray(array)
3
4 if !b {
5 return arr
6 }
7
8 for i := 0; i < len(array); i++ {
9 for j := len(array) - 1; j > i; j-- {
10 if sum == array[i]+array[j] {
11 return []int{array[i], array[j]}
12 }
13 }
14 }
15
16 return []int{}
17}
直接两层 for 循环,如何匹配到数组两个位置的值等于传入的和,则直接返回。此方法简单易懂,可读性高。
- 时间复杂度 O(n^2)
- 空间复杂度 O(1)
- 缓存法
1// TwoSumMap map 缓存法
2func TwoSumMap(sum int, array []int) []int {
3 b, arr := checkArray(array)
4
5 if !b {
6 return arr
7 }
8
9 // 通过 map 缓存数据
10 cache := make(map[int]int, len(array))
11 for i := range array {
12 cache[array[i]] = i
13 }
14
15 // 返回值在数组中的位置
16 for i := range array {
17 // 通过减法找到另一个值,直接去 map 查找
18 if _, ok := cache[sum-array[i]]; ok {
19 return []int{array[i], sum - array[i]}
20 }
21 }
22
23 return []int{}
24}
借助 map 把数组的值进行了缓存,用到了加法变减法的思路根据 hash 算法可以直接找到对应的另一个值是否存在。这个写法很直观,比第一种暴力法更加简单,建议平日小数量的时候直接用就行。
- 时间复杂度 O(n)
- 空间复杂度 O(2n)
- 双指针法
1func TwoSum2Point(sum int, array []int) []int {
2 b, arr := checkArray(array)
3
4 if !b {
5 return arr
6 }
7
8 left, right := 0, len(array)-1
9 for left < right {
10 s := array[left] + array[right]
11 if sum == s {
12 return []int{array[left], array[right]}
13 } else if sum > s {
14 left++
15 } else {
16 right--
17 }
18 }
19
20 return []int{}
21}
双指针法是字符查找的时候经常使用的方法,在数据量大的场景下会比较有优势。它的写法代码看着比较高级。
2.2 题目二
思考:
- 先要回想下什么是中位数,奇偶的处理方式是不一样的
- 找到截断的位置,计算中位数涉及到的数字的 index
偶数中位数的一个例子:
代码:
1// MiddleNum 算中位数
2func MiddleNum(nums []int) (float32, error) {
3 l := len(nums)
4 if l <= 0 {
5 return 0, illegalArray
6 }
7
8 if l == 1 {
9 return float32(nums[0]), nil
10 } else if l == 2 {
11 return float32((nums[0] + nums[1]) / 2), nil
12 }
13
14 p := Point(nums)
15
16 if isEven(l) {
17 target1 := l / 2
18 target2 := l/2 + 1
19 return (float32(nums[Position(l, p, target1)]) + float32(nums[Position(l, p, target2)])) / 2, nil
20 } else {
21 return float32(nums[Position(l, p, (l+1)/2)]), nil
22 }
23}
24
25// Point 得到拐点
26func Point(nums []int) int {
27 if len(nums) < 3 {
28 return 0
29 }
30
31 n, flag := nums[0], -1
32
33 for i := 1; i < len(nums); i++ {
34 cf := -1
35 c := nums[i]
36 if c < n {
37 cf = 1 // 降
38 } else if c > n {
39 cf = 0 // 升
40 }
41
42 if flag >= 0 && cf >= 0 && cf != flag {
43 return i
44 }
45
46 n = c
47 if cf >= 0 {
48 flag = cf
49 }
50 }
51
52 return 0
53}
54
55// Position 获取位置
56func Position(l, p, t int) int {
57 if l-p > t {
58 return p + t - 1
59 } else {
60 return t + p - l - 1
61 }
62}