leetcode-贪心算法

目录

455. 分发饼干

1005. k次取反后最大化的数组和

860. 柠檬水找零

376. 摆动序列(序列问题)

738. 单调递增的数字(序列问题)

122. 买卖股票的最佳时机ii(股票问题)

714. 买卖股票的最佳时机含手续费(股票问题)

135. 分发糖果(两个维度权衡问题)

406. 根据身高重建队列(两个维度权衡问题)

55. 跳跃游戏(区间问题)

45. 跳跃游戏ii(区间问题)

452. 用最少数量的箭引爆气球(区间问题)

435. 无重叠区间(区间问题)

763. 划分字母区间(区间问题)

56. 合并区间(区间问题)

53. 最大子序列和

134. 加油站

968. 监控二叉树


局部最优推出全局最优

解题步骤:

1. 将问题分成若干个子问题

2. 找出合适的贪心策略

3. 求解每一个子问题的最优解

4. 将局部最优解堆叠成全局最优解

455. 分发饼干

class Solution(object):
    def findContentChildren(self, g, s):
        """
        :type g: List[int]
        :type s: List[int]
        :rtype: int
        """
        n_children,  n_biscuits = len(g), len(s)
        g.sort()  # 小孩胃口值
        s.sort()  # 饼干尺寸值
        i, j, count = 0, 0, 0
        while i < n_children and j < n_biscuits:
            if s[j] >= g[i]:
                count += 1
                i += 1
                j += 1
            else:
                j += 1
        return count

1005. k次取反后最大化的数组和

class Solution(object):
    def largestSumAfterKNegations(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        # 将nums按绝对值从大到小排列
        nums = sorted(nums, key=abs, reverse=True)
        for i in range(len(nums)):
            # 从后向前遇到负数变成整数
            if k > 0 and nums[i] < 0:
                nums[i] *= -1
                k -= 1
        if k > 0:
            nums[-1] *= (-1) ** k  # 取A最后一个数只需要写-1
        return sum(nums)

860. 柠檬水找零

收到20美元优先用10+5找零

import collections
class Solution(object):
    def lemonadeChange(self, bills):
        """
        :type bills: List[int]
        :rtype: bool
        """
        hashtable = collections.defaultdict(int)
        i = 0
        while i < len(bills):
            hashtable[bills[i]] += 1
            if bills[i] == 10:
                hashtable[5] -= 1
            elif bills[i] == 20:
                if hashtable[10] > 0:
                    hashtable[10] -= 1
                    hashtable[5] -= 1
                else:
                    hashtable[5] -= 3
            for key in hashtable:
                if hashtable[key] < 0:
                    return False
            i += 1
        return True

376. 摆动序列(序列问题)

# 找递增/递减的段数
class Solution(object):
    def wiggleMaxLength(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        count = 1
        flag = 0
        if len(nums) == 1: return 1
        for i in range(1, len(nums)):
            if nums[i-1] < nums[i]:
                if not flag or flag == -1:
                    flag = 1
                    count += 1
            elif nums[i-1] > nums[i]:
                if not flag or flag == 1:
                    flag = -1
                    count += 1
            else:
                continue
        return count

738. 单调递增的数字(序列问题)

class Solution(object):
    def monotoneIncreasingDigits(self, n):
        """
        :type n: int
        :rtype: int
        """
        li = list(str(n))
        n_len = len(li)
        for i in range(n_len - 1, 0, -1):
            if int(li[i]) < int(li[i - 1]):
                # 当前位-1,后面的位全都变成9
                li[i - 1] = str(int(li[i - 1]) - 1)
                li[i:] = '9' * (n_len - i)
        return int("".join(li))

122. 买卖股票的最佳时机ii(股票问题)

class Solution(object):
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        ans = 0
        pre = prices[0]
        for i in range(len(prices)):
            if prices[i] > pre:
                ans += prices[i] - pre
            pre = prices[i]
        return ans

714. 买卖股票的最佳时机含手续费(股票问题)

class Solution(object):
    def maxProfit(self, prices, fee):
        """
        :type prices: List[int]
        :type fee: int
        :rtype: int
        """
        ans = 0
        pre = prices[0]
        for i in range(1, len(prices)):
            # 当前价格小于最低点则更新最低点
            if prices[i] < pre:
                pre = prices[i]
            # 当前价格高于最低点但是不赚钱
            elif pre <= prices[i] <= pre + fee:
                continue
            # 当前价格卖出赚钱
            else:
                ans += prices[i] - pre - fee
                # 如果下一个点的值更高,在这里就不卖了
                pre = prices[i] - fee
        return ans

135. 分发糖果(两个维度权衡问题)

两个维度权衡问题需要先确定一个维度,再考虑另一个维度,不然会顾此失彼。

class Solution(object):
    def candy(self, ratings):
        """
        :type ratings: List[int]
        :rtype: int
        """
        li = [0 for _ in range(len(ratings))]
        li[0] = 1
        # 比较右孩子是否比左孩子大
        for i in range(len(li)-1):
            if ratings[i] < ratings[i+1]:
                li[i+1] = li[i] + 1
            else:
                li[i+1] = 1
        # 比较左孩子是否比右孩子大
        for j in range(len(li)-1, 0, -1):
            if ratings[j-1] > ratings[j]:
                li[j-1] = max(li[j] + 1, li[j-1])
        return sum(li)

406. 根据身高重建队列(两个维度权衡问题)

# 将people按照lambda规则排序
# 1. peo[0]从大到小排序
# 2. peo[0]相等的情况下,peo[1]从小到大排序
# peo[i]是people中的每个元素
people.sort(key=lambda peo:(-peo[0], peo[1]))
class Solution(object):
    def reconstructQueue(self, people):
        """
        :type people: List[List[int]]
        :rtype: List[List[int]]
        """
        queue = []
        people.sort(key=lambda peo:(-peo[0], peo[1]))
        for val in people:
            queue.insert(val[1], val)
        return queue

55. 跳跃游戏(区间问题)

class Solution(object):
    def canJump(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        n = len(nums)
        maxrange = 0
        for i in range(n):
            if i <= maxrange:
                maxrange = max(maxrange, i+nums[i])
                if maxrange >= n-1:
                    return True
        return False

45. 跳跃游戏ii(区间问题)

class Solution(object):
    def jump(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        n = len(nums)-1
        i = 0
        count = 0
        while i <= n:
            if i == n :
                return count
            if i + nums[i] < n:
                maxrange = i + nums[i] + nums[i + nums[i]]
                tmp = nums[i]
                for step in range(1, nums[i]+1):
                    twostep = i + step + nums[i+step]
                    if twostep > maxrange:
                        maxrange = twostep
                        tmp = step
                i += tmp
                count += 1
            else:
                count += 1
                return count

452. 用最少数量的箭引爆气球(区间问题)

计算重叠气球最小右边界进行分组,气球的组数即为需要弓箭数

class Solution(object):
    def findMinArrowShots(self, points):
        """
        :type points: List[List[int]]
        :rtype: int
        """
        points.sort(key=lambda poi: (poi[0], poi[1]))
        ans = 1
        i = 0
        right = points[0][1]
        while i < len(points):
            if points[i][0] <= right:
                right = min(right, points[i][1])
            else:
                right = points[i][1]
                ans += 1
            i += 1
        return ans

435. 无重叠区间(区间问题)

 只按照右边界排序即可(从左向右遍历,优先选右边界小的)

class Solution(object):
    def eraseOverlapIntervals(self, intervals):
        """
        :type intervals: List[List[int]]
        :rtype: int
        """
        intervals.sort(key=lambda inter:inter[1])
        i = 1
        ans = 0
        right = intervals[0][1]
        while i < len(intervals):
            # 当前区间与上一区间右边重叠
            if intervals[i][0] < right:
                ans += 1
            else:
                right = intervals[i][1]
            i += 1
        return ans

763. 划分字母区间(区间问题)

import collections
class Solution(object):
    def partitionLabels(self, s):
        """
        :type s: str
        :rtype: List[int]
        """
        ans = []
        hashtable = collections.defaultdict(int)
        # 统计每个字母最后出现的坐标
        for i in range(len(s)):
            hashtable[s[i]] = i
        index = 0
        pre = 0
        right = hashtable[s[index]]
        while index < len(s):
            right = max(right, hashtable[s[index]])
            if index == right:
                ans.append(index+1-pre)
                pre = index+1
                index += 1
                continue
            right = max(right, hashtable[s[index]])
            index += 1

        return ans

56. 合并区间(区间问题)

class Solution(object):
    def merge(self, intervals):
        """
        :type intervals: List[List[int]]
        :rtype: List[List[int]]
        """
        intervals.sort(key=lambda x: x[0])

        merged = []
        for interval in intervals:
            # 如果列表为空,或者当前区间与上一区间不重合,直接添加
            if not merged or merged[-1][1] < interval[0]:
                merged.append(interval)
            else:
                # 否则的话,我们就可以与上一区间进行合并
                merged[-1][1] = max(merged[-1][1], interval[1])

        return merged

53. 最大子序列和

# 动态规划
class Solution(object):
    def maxSubArray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        dp = [0 for _ in range(len(nums))]
        dp[0] = nums[0]
        for i in range(1, len(nums)):
            dp[i] = max(dp[i-1] + nums[i], nums[i])
        return max(dp)
class Solution(object):
    def maxSubArray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        result = -float('inf')
        ans = 0
        for i in range(len(nums)):
            ans += nums[i]
            if ans > result:
                result = ans
            if ans <= 0:
                ans = 0
        return result

134. 加油站

class Solution(object):
    def canCompleteCircuit(self, gas, cost):
        """
        :type gas: List[int]
        :type cost: List[int]
        :rtype: int
        """
        rest = []
        for i in range(len(gas)):
            rest.append(gas[i]-cost[i])
        cur_res = [rest[0]]
        for i in range(1, len(rest)):
            cur_res.append(cur_res[i-1]+rest[i])
        min_res = min(cur_res)
        if min_res > 0: return 0
        start = len(rest)-1
        while start > -1:
            min_res += rest[start]
            if min_res >= 0:
                break
            start -= 1
        return start

968. 监控二叉树

局部最优:叶子节点的父节点上放摄像头

全局最优:用局部最优推出

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
# 不会用nonlocal用self.result代替了
class Solution(object):
    def minCameraCover(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        # 0:无覆盖
        # 1:有监控
        # 2:有覆盖
        self.result = 0

        # 按后序遍历
        def dfs(cur):
            if not cur: return 2
            left = dfs(cur.left)
            right = dfs(cur.right)
            if left == 2 and right == 2:
                return 0
            elif left == 0 or right == 0:
                self.result += 1
                return 1
            elif left == 1 or right == 1:
                return 2
        
        if dfs(root)==0:
            self.result += 1
        return self.result


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值