算法图解--学习笔记(贪婪算法)

263 阅读2分钟

关键词

  • 贪婪算法
  • 近似算法
  • NP完全问题
  • 集合(Set)

集合计算

Set

并集

并集意味着将集合合并

set1 | set2 = 两个集合的合并
交集

交集意味着找出两个集合中都有的元素

set1 & set2 = 两个集合相同的部分
差集

差集意味着将从一个集合中剔除出现在另一个集合中的元素

set1 - set2 = 从set1里面减掉出现在set2的元素

解决问题

贪婪算法是为了解决一些NP完全问题,因为NP完全问题,一般随着图中的点越来越多时,算法也是越来越耗时,时间大到无法接受,所以使用贪婪算法能够快速得到一个近似的最优解。(虽然可能不是最优解)

算法时间复杂度

O(n)

基本上只需要遍历一次就能找到近似解,所以时间复杂度为O(n)

练习

比如:教室安排问题,尽可能多课程安排在一个教室上。

  1. 9:00~10:00 英语课
  2. 9:30~10:30 政治课
  3. 10:00~11:00 数学课
  4. 10:30~11:30 体育课
  5. 11:00~12:00 语文课
// 假设课程时间已经按照时间排好序
type Course struct  {
	start int
	end int
	name string
}

func Greedy(arr []Course) (res []Course) {
    results  := make([]Course, 0)
    for currIndex, curr := range arr {
        // 假设第一个是最早结束或者最早开始的课程
        if len(results) == 0 {
            results = append(results, curr)
        } else {
            prev := results[len(results) - 1]
            var next Course
            if prev.end <= curr.start {
                next = curr
                // 如果课程已经按照start或者end排好序了,那么就不需要这个for循环了
                for i := currIndex + 1; i < len(arr); i++ {
                    temp := arr[i]
                    if prev.end <= temp.start && temp.start < next.start {
                        next = temp
                    }
                }
            }
            results = append(results, next)
        }
    }
    return results
}

func main() {
    c1 := Course{ start: 900, end: 1000, name: "英语课" }
    c4 := Course{ start: 1030, end: 1130, name: "体育课" }
    c3 := Course{ start: 1000, end: 1100, name: "数学课" }
    c2 := Course{ start: 930, end: 1030, name: "政治课" }
    c5 := Course{ start: 1100, end: 1200, name: "语文课" }
    arr := []Course{c1, c2, c3, c4, c5};
    results := Greedy(arr)
    fmt.Println("课程安排", results)
}

// 输出结果
$ go run main.go
课程安排 [{900 1000 英语课} {0 0 } {1000 1100 数学课} {0 0 } {1100 1200 语文课}]

小结

  • 会识别什么是NP完全问题
  • 遇到NP完全问题,使用贪婪算法,找到一个局部最优解
  • 贪婪算法实现简单,快速