【Leetcode刷题记录】-简单难度-贪心算法

【Leetcode刷题记录】-简单难度-贪心算法

  • 一、贪心算法
    • 1.基本概念
    • 2.贪心算法的基本思路
    • 3.算法存在的问题
  • 二、与贪心算法相关的题目
    • 1.分割平衡字符串
      • 题目
      • 代码
    • 2.分发饼干
      • 题目
      • 思路
      • 代码
    • 3.模拟行走机器人
      • 题目
      • 思路
      • 代码
  • 总结

一、贪心算法

1.基本概念

所谓贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,它所做出的仅仅是在某种意义上的局部最优解。
选择的贪心策略必须具备无后效性(即某个状态以后的过程不会影响以前的状态,只与当前状态有关。)

2.贪心算法的基本思路

  • 建立数学模型来描述问题
  • 把求解的问题分成若干个子问题
  • 对每个子问题求解,得到子问题的局部最优解
  • 把子问题的解局部最优解合成原来问题的一个解

3.算法存在的问题

  • 不能保证求得的最后解是最佳的
  • 不能用来求最大值或最小值的问题
  • 只能求满足某些约束条件的可行解的范围

二、与贪心算法相关的题目

1.分割平衡字符串

题目

在一个「平衡字符串」中,‘L’ 和 ‘R’ 字符的数量是相同的。

给出一个平衡字符串 s,请你将它分割成尽可能多的平衡字符串。

返回可以通过分割得到的平衡字符串的最大数量。
示例1

输入:s = “RLRRLLRLRL”
输出:4
解释:s 可以分割为 “RL”, “RRLL”, “RL”, “RL”, 每个子字符串中都包含相同数量的 ‘L’ 和 ‘R’。

示例2

输入:s = “LLLLRRRR”
输出:1
解释:s 只能保持原样 “LLLLRRRR”.

代码

class Solution:
    def balancedStringSplit(self, s: str) -> int:
        num = 0
        result = 0
        for c in s:
            if c == "R":
                num += 1
            else:
                num -= 1
            if not num:
                result += 1
        return result

2.分发饼干

题目

假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
注意:
你可以假设胃口值为正。
一个小朋友最多只能拥有一块饼干。
示例1

输入: [1,2,3], [1,1]
输出: 1
解释:
你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。
虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。
所以你应该输出1。

思路

如果当前饼干满足胃口,则处理下一个饼干和孩子。贪婪体现在每次只关注一个小孩的胃口。

代码

class Solution:
    def findContentChildren(self, g: List[int], s: List[int]) -> int:
        g.sort(reverse = False)
        s.sort(reverse = False)
        kid = 0
        cookie = 0
        result = 0
        while kid < len(g) and cookie < len(s):
            if s[cookie] >= g[kid]:
                kid += 1
                cookie += 1
                result += 1
            elif s[cookie] < g[kid]:
                cookie += 1

        return result

3.模拟行走机器人

题目

机器人在一个无限大小的网格上行走,从点 (0, 0) 处开始出发,面向北方。该机器人可以接收以下三种类型的命令:

  • -2:向左转 90 度
  • -1:向右转 90 度
  • 1 <= x <= 9:向前移动 x 个单位长度

在网格上有一些格子被视为障碍物。
第 i 个障碍物位于网格点 (obstacles[i][0], obstacles[i][1])
机器人无法走到障碍物上,它将会停留在障碍物的前一个网格方块上,但仍然可以继续该路线的其余部分。
返回从原点到机器人所有经过的路径点(坐标为整数)的最大欧式距离的平方。

示例1

输入: commands = [4,-1,3], obstacles = []
输出: 25
解释: 机器人将会到达 (3, 4)

示例2

输入: commands = [4,-1,4,-2,4], obstacles = [[2,4]]
输出: 65
解释: 机器人在左转走到(1, 8) 之前将被困在 (1, 4) 处

思路

分析:
1.不同的方向,向左和向右是不一样的,比如方向向左,这个方向左方向是向下的,所以相应的y坐标应减少。可以用字典的方法保存不同方向所做出的不同行动。
2.障碍物题目中给出是列表的形式,若使用题目中的形式会超时,这时应该将障碍物转化为集合的形式
3.一定要假设走一步,看是否遇到障碍物,因为若遇到障碍物会停留在障碍物的前一步。遇到障碍物则break跳出循环

代码

class Solution:
    def robotSim(self, commands: List[int], obstacles: List[List[int]]) -> int:
        dirction = {
     "up":{
     0:[0,1],-2:"left",-1:"right"},
        "down":{
     0:[0,-1],-2:"right",-1:"left"}, 
        "left":{
     0:[-1,0],-2:"down",-1:"up"}, 
        "right":{
     0:[1,0],-2:"up",-1:"down"}}

        curDir = "up"
        cord  = [0,0]
        res = 0
        obstacles = set(map(tuple, obstacles))
        for cd in commands:
            if cd < 0:
                curDir = dirction[curDir][cd]
            else:
                for i in range(1,cd+1):
                    tempx = cord[0] + dirction[curDir][0][0]
                    tempy = cord[1] + dirction[curDir][0][1]
                    if (tempx, tempy) in obstacles:
                        break
                    else:
                        cord = [tempx, tempy]
        
            res = max(res, cord[0]**2+cord[1]**2)
        return res

总结

感觉上面的3个题目只能体会出少许贪心算法的思想,他们都是涉及将大问题化成小问题,着重于局部忽略整体。感觉其他在网上看到的常见贪心算法的题目会更好地体现贪心如背包问题。

能使用贪心算法的前提:

  • 原问题复杂度高
  • 求全局最优解很复杂:模型难建立、计算复杂
  • 没必要去求解全局最优,“比较优”即可

你可能感兴趣的:(leetcode,python,算法)