贪心

455分发饼干

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

注意:

你可以假设胃口值为正。

一个小朋友最多只能拥有一块饼干。

示例 1:

  1. 输入: [1,2,3], [1,1]
  2. 输出: 1

解释:

你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。

虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。

所以你应该输出1。

示例 2:

  1. 输入: [1,2], [1,2,3]
  2. 输出: 2

解释:

你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。

你拥有的饼干数量和尺寸都足以让所有孩子满足。

所以你应该输出2.

题解

为了满足最多的孩子,应该尽量让胃口小的吃小饼干, 把胃口小的先满足。将孩子胃口,和饼干都升序排列,这里还用了两个指针。

  1. class Solution:
  2. def findContentChildren(self, g: List[int], s: List[int]) -> int:
  3. g.sort()
  4. s.sort()
  5. i,j = 0,0
  6. count = 0
  7. while True:
  8. if i>=len(g) or j>=len(s):
  9. break
  10. if g[i]<=s[j]:
  11. count += 1
  12. i += 1
  13. j += 1
  14. return count

435无重叠区间

给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。

注意:

可以认为区间的终点总是大于它的起点。

区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。

示例 1:

  1. 输入: [ [1,2], [2,3], [3,4], [1,3] ]
  2. 输出: 1

解释: 移除 [1,3] 后,剩下的区间没有重叠。

示例 2:

  1. 输入: [ [1,2], [1,2], [1,2] ]
  2. 输出: 2

解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。

示例 3:

  1. 输入: [ [1,2], [2,3] ]
  2. 输出: 0

解释: 你不需要移除任何区间,因为它们已经是无重叠的了。

题解

在每次选择中,区间的结尾最为重要,选择的区间结尾越小,尽可能留给后面的区间的空间越大,那么后面能够选择的区间个数也就越大。

按区间的结尾进行排序,每次选择结尾最小,并且和前一个区间不重叠的区间。

  1. class Solution:
  2. def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
  3. if not intervals:
  4. return 0
  5. intervals.sort(key=lambda x: x[1]) # 注意这里是按照第二个元素来排序
  6. count = 0
  7. end = intervals[0][1] # 初始化end
  8. for i in range(1,len(intervals)):
  9. if intervals[i][0] < end:
  10. count += 1
  11. else:
  12. end = intervals[i][1] # 更新end
  13. return count

402移掉K位数字

给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小。

注意:

num 的长度小于 10002 且 ≥ k。

num 不会包含任何前导零。

示例 1 :

  1. 输入: num = "1432219", k = 3
  2. 输出: "1219"

解释: 移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219。

示例 2 :

  1. 输入: num = "10200", k = 1
  2. 输出: "200"

解释: 移掉首位的 1 剩下的数字为 200. 注意输出不能有任何前导零。

示例 3 :

  1. 输入: num = "10", k = 2
  2. 输出: "0"

解释: 从原数字移除所有的数字,剩余为空就是0。

这道题主要思路:当指针指向的数比左边的数小,那么舍弃左边的数,在删除数字时应该从左向右迭代,这样的数整体最小。这里用到栈的思想,也就是一个列表。

  1. class Solution:
  2. def removeKdigits(self, num: str, k: int) -> str:
  3. numStack = []
  4. for i in num:
  5. while k and numStack and numStack[-1]>i: #这里循环是为了将i与栈内的所有数进行比较,保证整体最小。
  6. numStack.pop()
  7. k -= 1
  8. numStack.append(i)
  9. numStack = numStack[:-k] if k else numStack
  10. return ''.join(numStack).lstrip('0') or '0'

452用最少数量的箭引爆气球

在二维空间中有许多球形的气球。对于每个气球,提供的输入是水平方向上,气球直径的开始和结束坐标。由于它是水平的,所以y坐标并不重要,因此只要知道开始和结束的x坐标就足够了。开始坐标总是小于结束坐标。平面内最多存在104个气球。

一支弓箭可以沿着x轴从不同点完全垂直地射出。在坐标x处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 且满足  xstart ≤ x ≤ xend,则该气球会被引爆。可以射出的弓箭的数量没有限制。 弓箭一旦被射出之后,可以无限地前进。我们想找到使得所有气球全部被引爆,所需的弓箭的最小数量。

  1. Example:
  2. 输入:
  3. [[10,16], [2,8], [1,6], [7,12]]
  4. 输出:
  5. 2

解释:

对于该样例,我们可以在x = 6(射爆[2,8],[1,6]两个气球)和 x = 11(射爆另外两个气球)。

这道题也是计算区间重叠的个数,和上面那道差不多。按每个区间end升序排列。

  1. class Solution:
  2. def findMinArrowShots(self, points: List[List[int]]) -> int:
  3. if len(points)==0:
  4. return 0
  5. points.sort(key=lambda x:x[1])
  6. end = points[0][1]
  7. count = 1
  8. for i in range(1,len(points)):
  9. if points[i][0]<=end:
  10. continue
  11. else:
  12. end = points[i][1]
  13. count+=1
  14. return count

406. 根据身高重建队列

假设有打乱顺序的一群人站成一个队列。 每个人由一个整数对(h, k)表示,其中h是这个人的身高,k是排在这个人前面且身高大于或等于h的人数。 编写一个算法来重建这个队列。

注意:

总人数少于1100人。

示例

  1. 输入:
  2. [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
  3. 输出:
  4. [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]

让我们从最简单的情况下思考,当队列中所有人的 (h,k) 都是相同的高度 h,只有 k 不同时,解决方案很简单:每个人在队列的索引 index = k。

即使不是所有人都是同一高度,这个策略也是可行的。因为个子矮的人相对于个子高的人是 “看不见” 的,所以可以先安排个子高的人。



上图中我们先安排身高为 7 的人,将它放置在与 k 值相等的索引上;再安排身高为 6 的人,同样的将它放置在与 k 值相等的索引上。

该策略可以递归进行:

  • 将最高的人按照 k 值升序排序,然后将它们放置到输出队列中与 k 值相等的索引位置上。
  • 按降序取下一个高度,同样按 k 值对该身高的人升序排序,然后逐个插入到输出队列中与 k 值相等的索引位置上。
  • 直到完成为止

在python里直接用list.insert(index, i)在Index处插入。最高的人中,肯定有一个人排他前面人数是0,所以我们这里插入第一个肯定是[最高的身高,0]这样

  1. class Solution:
  2. def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]:
  3. if len(people)<2:
  4. return people
  5. result = []
  6. people.sort(key=lambda x:(-x[0],x[1]))
  7. for i in people:
  8. result.insert(i[1], i)
  9. return result

121. 买卖股票的最佳时机

121

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。

注意你不能在买入股票前卖出股票。

示例 1:

  1. 输入: [7,1,5,3,6,4]
  2. 输出: 5
  3. 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5
  4. 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
  5. 示例 2:
  6. 输入: [7,6,4,3,1]
  7. 输出: 0
  8. 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0

只要记录前面的最小价格,将这个最小价格作为买入价格,然后将当前的价格作为售出价格,查看当前收益是不是最大收益。

查看评论后,把它看作DP问题理解起来简单点。

假设当前在第 i 天,令 minPrice 表示前 i-1 天的最低价格;令 maxProfit 表示前 i-1 天的最大收益。那么考虑第 i 天的收益时,存在两种情况:

  • 在第 i 天卖出。很显然,想要获得最大收益,应该在前 i-1 天中价格最低的时候买入,即此时的收益为:prices[i] - minPrice。(可能会出现负数,但是没关系)
  • 不在第 i 天卖出。那么第 i 天的最大收益就等于前 i -1 天中的最大收益

状态转移方程为:第 i 天最大收益 = max( 在第 i 天卖出的所得收益 , 前 i-1 天的最大收益)

题解

  1. class Solution:
  2. def maxProfit(self, prices: List[int]) -> int:
  3. if len(prices)==0:
  4. return 0
  5. Min = prices[0]
  6. Max = 0
  7. for i in range(1,len(prices)):
  8. temp = prices[i] - Min
  9. Max = max(Max, temp)
  10. Min = min(Min, prices[i])
  11. return Max

贪心做法

只允许一笔交易,在从左往右扫描数组的过程中,保存当前的最小值,结果就是ans = max(ans, price[i]-Min),保证ans时刻保存了当前最大收益。

  1. class Solution:
  2. def maxProfit(self, prices: List[int]) -> int:
  3. if len(prices)==0:
  4. return 0
  5. Min, ans = prices[0], 0
  6. for i in range(len(prices)):
  7. if Min>=prices[i]:
  8. Min = prices[i]
  9. continue
  10. else:
  11. ans = max(ans, prices[i] - Min)
  12. return ans

188. 买卖股票的最佳时机 IV(这类题通解)

参考LeetCode

763. 划分字母区间

763

字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一个字母只会出现在其中的一个片段。返回一个表示每个字符串片段的长度的列表。

示例 1:

  1. 输入: S = "ababcbacadefegdehijhklij"
  2. 输出: [9,7,8]
  3. 解释:
  4. 划分结果为 "ababcbaca", "defegde", "hijhklij"
  5. 每个字母最多出现在一个片段中。
  6. "ababcbacadefegde", "hijhklij" 的划分是错误的,因为划分的片段数较少。

对于遇到的每一个字母,去找这个字母最后一次出现的位置,用来更新当前的最小区间。参考

定义数组 last[char] 来表示字符 char 最后一次出现的下标。定义 anchor 和 j 来表示当前区间的首尾。如果遇到的字符最后一次出现的位置下标大于 j, 就让 j=last[c] 来拓展当前的区间。当遍历到了当前区间的末尾时(即 i==j ),把当前区间加入答案,同时将 start 设为 i+1 去找下一个区间。

  1. class Solution(object):
  2. def partitionLabels(self, S):
  3. last = {c: i for i, c in enumerate(S)} # 构建一个字典来保存每个字符最后一次出现位置,很巧妙。
  4. j = anchor = 0
  5. ans = []
  6. for i, c in enumerate(S):
  7. j = max(j, last[c])
  8. if i == j:
  9. ans.append(i - anchor + 1)
  10. anchor = i + 1
  11. return ans

leetcode刷题-- 4. 贪心的更多相关文章

  1. LeetCode刷题笔记-贪心法-格雷编码

    题目描述: 格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异. 给定一个代表编码总位数的非负整数 n,打印其格雷编码序列.格雷编码序列必须以 0 开头. 来源:力扣(Leet ...

  2. C#LeetCode刷题-贪心算法

    贪心算法篇 # 题名 刷题 通过率 难度 44 通配符匹配   17.8% 困难 45 跳跃游戏 II   25.5% 困难 55 跳跃游戏   30.6% 中等 122 买卖股票的最佳时机 II C ...

  3. 看完互联网大佬的「LeetCode 刷题手册」, 手撕了 400 道 Leetcode 算法题

    大家好,我是 程序员小熊 ,来自 大厂 的程序猿.相信绝大部分程序猿都有一个进大厂的梦想,但相较于以前,目前大厂的面试,只要是研发相关岗位,算法题基本少不了,所以现在很多人都会去刷 Leetcode ...

  4. LeetCode刷题专栏第一篇--思维导图&时间安排

    昨天是元宵节,过完元宵节相当于这个年正式过完了.不知道大家有没有投入继续投入紧张的学习工作中.年前我想开一个Leetcode刷题专栏,于是发了一个投票想了解大家的需求征集意见.投票于2019年2月1日 ...

  5. leetcode 刷题进展

    最近没发什么博客了 凑个数 我的leetcode刷题进展 https://gitee.com/def/leetcode_practice 个人以为 刷题在透不在多  前200的吃透了 足以应付非算法岗 ...

  6. LeetCode刷题指南(字符串)

    作者:CYC2018 文章链接:https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Leetcode+%E9%A2%98%E8%A7% ...

  7. leetcode刷题记录--js

    leetcode刷题记录 两数之和 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但 ...

  8. LeetCode刷题总结之双指针法

    Leetcode刷题总结 目前已经刷了50道题,从零开始刷题学到了很多精妙的解法和深刻的思想,因此想按方法对写过的题做一个总结 双指针法 双指针法有时也叫快慢指针,在数组里是用两个整型值代表下标,在链 ...

  9. Leetcode刷题记录(python3)

    Leetcode刷题记录(python3) 顺序刷题 1~5 ---1.两数之和 ---2.两数相加 ---3. 无重复字符的最长子串 ---4.寻找两个有序数组的中位数 ---5.最长回文子串 6- ...

随机推荐

  1. c++中sort函数调用报错Expression : invalid operator <的内部原理

    当我们调用sort函数进行排序时,中的比较函数如果写成如下 bool cmp(const int &a, const int &b) { if(a!=b) return a<b; ...

  2. py2

    函数相关的 # 生成器相关的# 例1 ll = sum(i for i in range(100000000)) #生成器占资源少 # 例2 def demo(): for i in range(4) ...

  3. 【Vue CLI】从安装到构建项目再到目录结构的说明

    目录 1. 构建我们的项目 2. 目录结构说明 2.1 build目录 2.2 config目录 2.3 src目录 2.4 static目录 "Vue CLI是一个基于Vue.js进行快速 ...

  4. [洛谷P4463] calc (生成函数)

    首先注意到题目中 \(a\) 数组是有序的,那我们只用算有序的方案乘上 \(n!\) 即可. 而此时的答案显然 \[Ans=[x^n](1+x)(1+2x)\dots (1+Ax)=\prod_{i= ...

  5. P&R 3

    Floorplan: 要做好floorplan需要掌握哪些知识跟技能? 通常,遇到floorplan问题,大致的debug步骤跟方法有哪些? 如何衡量floorplan的QA? Floorplan是后 ...

  6. animation模块的使用

    1.动画的实现-初探 import numpy as np import matplotlib.pyplot as plt from matplotlib.animation import FuncA ...

  7. WEB前后端约定接口

  8. 6_3 矩阵链乘(UVa424)<用栈实现简单的表达式解析>

    假设你必须做A*B*C*D*E的运算,在这里A,B,C,D,E都是矩阵(matrix).由于矩阵相乘具有连接性(associative),所以相乘的顺序可以是任意的.然而所需要的基本乘法数却与不尽相同 ...

  9. 高级命令之awk

    1.提取文件内容 2.提取ip

  10. SQL表名,应该用表对应资源对象的复数形式还是单数形式

    原文:http://blog.csdn.net/lizeyang 问题 SQL表名,应该用表对应资源对象的复数形式还是单数形式.例如一个用户表,表名是用user还是users更合适呢?   精华回答 ...