算法题目 贪心算法

Posted by SunQH Blog on February 13, 2021

leetcode题目按类型

贪心算法

贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。

贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。

✅(20m) 455. 分发饼干

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

注意:

你可以假设胃口值为正。 一个小朋友最多只能拥有一块饼干。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
示例 1:

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

输出: 1

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

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

输出: 2

解释: 
你有两个孩子和三块小饼干2个孩子的胃口值分别是1,2
你拥有的饼干数量和尺寸都足以让所有孩子满足
所以你应该输出2.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution:
    def findContentChildren(self, g: List[int], s: List[int]) -> int:
        if len(g)==0 or len(s) == 0: return 0
        g.sort()
        s.sort()
        i = 0
        j = 0
        while i<len(g) and j<len(s):
            if s[j] >= g[i]:
                i += 1
            j += 1     
    
            
        return i
    
1
from typing import Listg = [1,2,3,2]s = [1,4]solution = Solution()result = solution.findContentChildren(g,s)result

✅(20m) 392. 判断子序列

给定字符串 s 和 t ,判断 s 是否为 t 的子序列。

你可以认为 s 和 t 中仅包含英文小写字母。字符串 t 可能会很长(长度 ~= 500,000),而 s 是个短字符串(长度 <=100)。

字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,”ace”是”abcde”的一个子序列,而”aec”不是)。

1
示例 1:s = "abc", t = "ahbgdc"返回 true.示例 2:s = "axc", t = "ahbgdc"返回 false.后续挑战 :如果有大量输入的 S称作S1, S2, ... , Sk 其中 k >= 10亿你需要依次检查它们是否为 T 的子序列在这种情况下你会怎样改变代码
1
# 双指针class Solution:    def isSubsequence(self, s: str, t: str) -> bool:        n, m = len(s), len(t)          i = j = 0        while i < n and j < m:            if t[j] == s[i]:                i += 1            j += 1        return i == n                

✅(50m) 55. 跳跃游戏

难度中等1089

给定一个非负整数数组 nums ,你最初位于数组的 第一个下标

数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标。

示例 1:

1
输入:nums = [2,3,1,1,4]输出:true解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。

示例 2:

1
输入:nums = [3,2,1,0,4]输出:false解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。

✅(40m) 45. 跳跃游戏 II

难度中等1004

给定一个非负整数数组,你最初位于数组的第一个位置。

数组中的每个元素代表你在该位置可以跳跃的最大长度。

你的目标是使用最少的跳跃次数到达数组的最后一个位置。

假设你总是可以到达数组的最后一个位置。

示例 1:

1
输入: [2,3,1,1,4]输出: 2解释: 跳到最后一个位置的最小跳跃数是 2。     从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。

示例 2:

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

2️⃣

1
    def jump(self, nums: List[int]) -> int:        max_pos, end, step = 0,0,0        for i in range(len(nums)-1):  # 注意,不需要到最后一个位置            max_pos = max(max_pos, nums[i]+i)            if i == end:                end = max_pos                step+=1        return step

for i in range(len(nums)-1): # 注意,不需要到最后一个位置

例如,如果只有一位,则返回0

✅(30m) 56. 合并区间

给出一个区间的集合,请合并所有重叠的区间。

1
示例 1:输入: [[1,3],[2,6],[8,10],[15,18]]输出: [[1,6],[8,10],[15,18]]解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].示例 2:输入: [[1,4],[4,5]]输出: [[1,5]]解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。
1
class Solution:    def merge(self, intervals: List[List[int]]) -> 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

2️⃣ (10m)

1
class Solution:    def merge(self, intervals: List[List[int]]) -> List[List[int]]:        intervals.sort()        res=[intervals[0]]        for num in intervals:            if res[-1][0] <= num[0] <= res[-1][1]:                res[-1][1] = max(res[-1][1],num[1])            else:                res.append(num)        return res

🚩(20m) 435. 无重叠区间

难度中等430

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

注意:

  1. 可以认为区间的终点总是大于它的起点。
  2. 区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。

示例 1:

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

示例 2:

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

示例 3:

1
输入: [ [1,2], [2,3] ]输出: 0解释: 你不需要移除任何区间,因为它们已经是无重叠的了。

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

难度中等421

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

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

给你一个数组 points ,其中 points [i] = [xstart,xend] ,返回引爆所有气球所必须射出的最小弓箭数。