美文网首页
贪心算法

贪心算法

作者: Eden0503 | 来源:发表于2022-06-15 02:49 被阅读0次

    [TOC]

    局部最优解->全局最优

    455. 分发饼干(简单/贪心)

    // g是胃口,s是饼干
    // 用大饼干优先满足胃口大的,并统计满足小孩数量。 https://leetcode.cn/problems/assign-cookies/solution/455-fen-fa-bing-gan-tan-xin-jing-dian-ti-o6k6/
    func findContentChildren(g []int, s []int) int {
        sort.Ints(g)
        sort.Ints(s)
    
        gLen := len(g)
        sLen := len(s)
    
        index := sLen - 1
        count := 0
        for i := gLen - 1; i > 0; i-- {
            if index >= 0 && s[index] >= g[i] {
                count++
                index--
            }
        }
        return count
    }
    

    392. 判断子序列(简单/贪心)

    452. 用最少数量的箭引爆气球(中等/贪心)

    // https://leetcode.cn/problems/minimum-number-of-arrows-to-burst-balloons/solution/yong-zui-shao-shu-liang-de-jian-yin-bao-qi-qiu-1-2/
    // 一定存在一种最优(射出的箭数最小)的方法,使得每一支箭的射出位置都恰好对应着某一个气球的右边界。
    func findMinArrowShots(points [][]int) int {
        // 按照右边界进行排序
        sort.Slice(points, func(i, j int) bool {
            return points[i][1] < points[j][1]
        })
    
        fmt.Println(points)
        count := 1 // 必定有一只箭
        end := points[0][1] 
        for i := 1; i < len(points); i++ {
            if points[i][0] > end { //前一个气球重点 < 当前气球起点,则数量+1,这里注意是point[i][0],注意是 > 
                count++
                end = points[i][1] //  这里注意是point[i][1]
            }
        }
        return count
    }
    

    435. 无重叠区间(中等/贪心)

    func eraseOverlapIntervals(intervals [][]int) int {
        sort.Slice(intervals, func(i, j int) bool {
            return intervals[i][1] < intervals[j][1]
        })
        fmt.Println(intervals)
        count := 1
        end := intervals[0][1]
        for i := 1; i < len(intervals); i++ {
            if intervals[i][0] >= end { // /当区间的左边界大于上一个区间的右边界的时候 说明是一对不重合区间,注意是 >=
                count++
                end = intervals[i][1]
            }
    
        }
        return len(intervals) - count // //intervals的长度减去最多的不重复的区间 就是最少删除区间的个数
    }
    

    1167. 连接棒材的最低费用(贪心/小顶堆)

    、、https://www.jianshu.com/p/80a3d7add522
    
    type intHeap []int
    
    func (key intHeap) Len() int {
        return len(key)
    }
    
    func (key intHeap) Less(i int, j int) bool {
        return key[i] < key[j]
    }
    
    func (key intHeap) Swap(i int, j int) {
        key[i], key[j] = key[j], key[i]
    }
    
    func (h *intHeap) Push(x interface{}) {
        *h = append(*h, x.(int))
    }
    
    func (h *intHeap) Pop() interface{} {
        old := *h
        n := len(old)
        x := old[n-1]
        *h = old[0 : n-1]
        return x
    }
    
    func (h *intHeap) push(x int) {
        heap.Push(h, x)
    }
    
    func (h *intHeap) pop() int {
        return heap.Pop(h).(int)
    }
    
    func connectSticks(sticks []int) int {
        res := 0
        sticksHeap := intHeap{}
        sticksHeap = sticks
        heap.Init(&sticksHeap)
        for sticksHeap.Len() > 1 {
            first, second := sticksHeap.pop(), sticksHeap.pop()
            sticksHeap.push(first+second)
            res += first+second
        }   
        return res
    }
    

    860. 柠檬水找零(简单/其实感觉没用到贪心)

    // 一开始我还想着利用map来存,我真是傻逼
    func lemonadeChange(bills []int) bool {
        five, ten := 0, 0
        for _, bill := range bills {
            if bill == 5 {
                five++
            } else if bill == 10 {
                if five == 0 {
                    return false
                }
                five--
                ten++
            } else {
                if five > 0 && ten > 0 {
                    five--
                    ten--
                } else if five >= 3 {
                    five -= 3
                } else {
                    return false
                }
            }
        }
        return true
    }
    
    

    56. 合并区间 (中等/感觉和贪心也没啥关系)

    
    // ================ 解法一 ====================================
    func merge(intervals [][]int) [][]int {
        //先从小到大排序
        sort.Slice(intervals, func(i, j int) bool {
            return intervals[i][0] < intervals[j][0]
        })
        //再弄重复的
        for i := 0; i < len(intervals)-1; i++ {
            // 当前右边界intervals[i][1]和下一区间左边界intervals[i+1][0]比较
            if intervals[i][1] >= intervals[i+1][0] {
                // 更新区间右边界最大值
                intervals[i][1] = max(intervals[i][1], intervals[i+1][1]) //赋值最大值
                // 删除下一个区间元素,因为此时当前区间右边界已经变了
                intervals = append(intervals[:i+1], intervals[i+2:]...) // 很重要,删除i+1这一行
                i--
            }
        }
        return intervals
    }
    
    func max(a, b int) int {
        if a > b {
            return a
        }
        return b
    }
    
    //  ====================  解法二(其实就是硬写,挺好理解的)  ============================
    func merge(intervals [][]int) [][]int {
        sort.Slice(intervals, func(i, j int) bool {
            return intervals[i][0] < intervals[j][0]
        })
        var res [][]int
        start, end := intervals[0][0], intervals[0][1]
        for i := 1; i < len(intervals); i++ {
            if intervals[i][0] <= end {
                if intervals[i][1] > end {
                    end = intervals[i][1]
                }
            } else {
                res = append(res, []int{start, end})
                start, end = intervals[i][0], intervals[i][1]
            }
        }
        return append(res, []int{start, end})
    }
    
    

    55 跳跃游戏

    跳跃游戏 II

    122. 买卖股票的最佳时机 II(中等/贪心)

    /*
    res =  (prices[3] - prices[2]) + (prices[2] - prices[1]) + (prices[1] - prices[0])
        =  prices[3] - prices[0]
    按照贪心算法,在下标为 1、2、3 的这三天,我们做的操作应该是买进昨天的,卖出今天的。
    等价于:在下标为 0 的那一天买入,在下标为 3 的那一天卖出。
    贪心算法的直觉:由于不限制交易次数,只要今天股价比昨天高,就交易。
    */
    
    func maxProfit(prices []int) (ans int) {
        for i := 1; i < len(prices); i++ {
            ans += max(0, prices[i]-prices[i-1])
        }
        return
    }
    

    数组拆分 I

    1710. 卡车上的最大单元数(简单/贪心)

    func maximumUnits(boxTypes [][]int, truckSize int) int {
        sort.Slice(boxTypes, func(i, j int) bool {
            return boxTypes[i][1] > boxTypes[j][1]
        })
        res := 0
        for _, v := range boxTypes {
            size := min(truckSize, v[0])
            res += size * v[1]
            truckSize -= size
        }
        return res
    }
    

    1217. 玩筹码(简单/贪心)

    交换字符使得字符串相同

    构造 K 个回文字符串

    921. 使括号有效的最少添加(中等/贪心)

    func minAddToMakeValid(S string) int {
        //left, right 分别表示左右未配对的括号
        left, right := 0, 0
        for _, s := range S {
            if s == '(' {
                left++
            } else if left > 0 && s == ')' {
                left--
            } else {
                right++
            }
        }
        return left + right
    }
    

    1029. 两地调度(中等/贪心)

    // 思路很重要:
    我们这样来看这个问题,公司首先将这 2N 个人全都安排飞往 B 市,
    再选出 N 个人改变它们的行程,让他们飞往 A 市。
    如果选择改变一个人的行程,那么公司将会额外付出 price_A - price_B 的费用,这个费用可正可负。
    因此最优的方案是,选出 price_A - price_B 最小的 N 个人,让他们飞往 A 市,其余人飞往 B 市。
    func twoCitySchedCost(costs [][]int) int {
        sort.Slice(costs, func(i, j int) bool {
            return (costs[i][0] - costs[i][1]) > (costs[j][0] - costs[j][1])
        })
    
        cost := 0
        for i := 0; i < len(costs)/2; i++ { // 去B城市的
            cost += costs[i][1]
        }
    
        for i := len(costs) / 2; i < len(costs); i++ { // 去A城市的
            cost += costs[i][0]
        }
    
        return cost
    }
    
    

    给定行和列的和求可行矩阵

    分发糖果

    最大子序和(不算贪心题吧)

    280. 摆动排序 (会员/中等/贪心)

    单调递增的数字

    移掉 K 位数字

    翻转矩阵后的得分

    555. 分割连接字符串(会员/中等/贪心)

    2144. 打折购买糖果的最小开销(简单/贪心)

    func minimumCost(cost []int) int {
        sort.Sort(sort.Reverse(sort.IntSlice(cost)))
        res := 0
        for i := range cost {
            if i%3 != 2 {
                res += cost[i]
            }
        }
        return res
    }
    

    2098. 长度为 K 的最大偶数和子序列(会员/中等/贪心)

    给你一个整数数组 nums 和一个整数 k 。找出 nums 长度为 k 的所有子序列中的 最大偶数和 。
    返回此总和,如果此总和不存在,则返回 -1。
    子序列 是一个数组,可以通过删除一些元素或不删除任何元素而从另一个数组派生,而不改变其余元素的顺序。
    
    输入: nums = [4,1,5,3,1], k = 3
    输出: 12
    解释:
    具有最大可能偶数和的子序列是[4,5,3]。它的和为 4 + 5 + 3 = 12
    
    /*
    思路:
    1、先降序排序,计算前K个数的和,如果是偶数,直接返回结果。如果是奇数,往下。
    2、求前k个数中, 最小的奇数和偶数
    3、求后n-k个数中最大的奇数和偶数
    4、前k个数和为奇数,故减去其中最小的奇/偶数,加上后n-k个数中最大的偶/奇数,两个值返回最大
    */
    func largestEvenSum(nums []int, k int) int64 {
    
        sort.Sort(sort.Reverse(sort.IntSlice(nums)))
    
        tempSum := 0
        for i := 0; i < k; i++ {
            tempSum += nums[i]
        }
    
        if tempSum%2 == 0 {
            return int64(tempSum)
        }
    
        minOdd := math.MaxInt32
        minEven := math.MaxInt32
    
        for i := 0; i < k; i++ {
            if nums[i]%2 != 0 && nums[i] < minOdd { //奇数
                minOdd = nums[i]
            }
    
            if nums[i]%2 == 0 && nums[i] < minEven {
                minEven = nums[i]
            }
        }
    
        maxOdd := math.MinInt32
        maxEven := math.MinInt32
    
        for i := k; i < len(nums); i++ {
            if nums[i]%2 != 0 && nums[i] > maxOdd { //奇数
                maxOdd = nums[i]
            }
    
            if nums[i]%2 == 0 && nums[i] > maxEven {
                maxEven = nums[i]
            }
        }
    
        // 前k个数和为奇数,故减去其中最小的奇/偶数,加上后n-k个数中最大的偶/奇数,两个值返回最大,这两个值也可能不存在
        ans1 := -1
        ans0 := -1
        if minOdd != math.MaxInt32 && maxEven != math.MinInt32 {
            ans1 = tempSum + maxEven - minOdd
        }
        if minEven != math.MaxInt32 && maxOdd != math.MinInt32 {
            ans0 = tempSum + maxOdd - minEven
        }
        return max(ans0, ans1)  // 不存在就返回-1
    }
    

    624. 数组列表中的最大距离(会员/中等/贪心)

    给定 m 个数组,每个数组都已经按照升序排好序了。现在你需要从两个不同的数组中选择两个整数(每个数组选一个)并且计算它们的距离。两个整数 a 和 b 之间的距离定义为它们差的绝对值 |a-b| 。你的任务就是去找到最大距离
    
     
    

    相关文章

      网友评论

          本文标题:贪心算法

          本文链接:https://www.haomeiwen.com/subject/mvitvrtx.html