763. Partition Labels

  1. class Solution:
  2. def partitionLabels(self, s: str) -> List[int]:
  3. dic = dict() # 记录char最后出现的位置
  4. for idx, ch in enumerate(s):
  5. dic[ch] = idx
  6. partition = []
  7. start = end = 0
  8. for idx, ch in enumerate(s):
  9. end = max(end, dic[ch])
  10. if idx == end:
  11. res.append(end - start + 1)
  12. start = end = idx + 1
  13. return partition
  • 时间复杂度:贪心 - 图1
  • 空间复杂度:贪心 - 图2

55. Jump Game

  1. class Solution:
  2. def canJump(self, nums: List[int]) -> bool:
  3. end = len(nums) - 1 # 终点
  4. rightmost = 0 # 最远可以到达的位置
  5. for index, num in enumerate(nums):
  6. if index > rightmost: # 当前位置已经不可达
  7. break
  8. rightmost = max(rightmost, index + num)
  9. if rightmost >= end:
  10. return True
  11. return False
  • 时间复杂度:贪心 - 图3
  • 空间复杂度:贪心 - 图4

45. Jump Game II

贪心 - 图5的位置逆向寻找上一步的位置,贪心地考虑,若上一步位置越靠前,则使用的步数越少。故正向遍历到当前位置。

  1. class Solution:
  2. def jump(self, nums: List[int]) -> int:
  3. position = len(nums) - 1
  4. steps = 0
  5. while position > 0:
  6. for i in range(position):
  7. if i + nums[i] >= position:
  8. position = i
  9. steps += 1
  10. break
  11. return steps
  • 时间复杂度:贪心 - 图6,考虑最坏情况,用例为贪心 - 图7
  • 空间复杂度:贪心 - 图8

正向考虑,注意不要访问最后一个元素

class Solution:
    def jump(self, nums: List[int]) -> int:
        rightmost = 0
        end_step = 0
        num_step = 0

        for index, num in enumerate(nums[:-1]):
            rightmost = max(rightmost, index + num)
            if index == end_step:
                num_step += 1
                end_step = rightmost
                if end_step >= len(nums) - 1:
                    break

        return num_step
  • 时间复杂度:贪心 - 图9
  • 空间复杂度:贪心 - 图10

135. Candy

每个孩子至少分到贪心 - 图11个糖果,且:
相邻两个孩子,评分更高的会获得更多的糖果 贪心 - 图12 满足**左右规则**

  • 左规则:若贪心 - 图13,则贪心 - 图14会得到更多糖果;
  • 右规则:若贪心 - 图15,则贪心 - 图16会得到更多糖果。

    class Solution:
      def candy(self, ratings: List[int]) -> int:
          n = len(ratings)
          candies = [1] * n
    
          for i in range(1, n):                    # 满足'左'规则
              if ratings[i-1] < ratings[i]:
                  candies[i] = candies[i-1] + 1
    
          for i in range(n - 2, -1, -1):           # 满足'右'规则
              if ratings[i] > ratings[i+1]:
                  candies[i] = max(candies[i], candies[i+1] + 1)
    
          return sum(candies)
    
  • 时间复杂度:贪心 - 图17

  • 空间复杂度:贪心 - 图18

31. Next Permutation

贪心思路:

  1. 拟寻找一个数对pair 贪心 - 图19,满足贪心 - 图20并且贪心 - 图21要尽可能靠右贪心 - 图22要尽可能(最接近a);
  2. 交换贪心 - 图23贪心 - 图24,并将贪心 - 图25后方的数字翻转

e56a66ed318d1761cd8c8f9d1521f82a30c71ecc84f551912b90d8fe254c8f3d-image.png

class Solution:
    def nextPermutation(self, nums: List[int]) -> None:
        n = len(nums)
        i = n - 2
        while i >= 0 and nums[i] >= nums[i + 1]:    # 逆序寻找'较小数'
            i -= 1

        if i >= 0:                                  # 排列不是全逆序
            j = n - 1
            while j > i and nums[i] >= nums[j]:
                j -= 1
            nums[i], nums[j] = nums[j], nums[i]

        left, right = i + 1, n - 1                  # 翻转后方元素(全逆序)
        while left < right:
            nums[left], nums[right] = nums[right], nums[left]
            left += 1
            right -= 1
  • 时间复杂度:贪心 - 图27
  • 空间复杂度:贪心 - 图28

低频:每日一题

942. DI String Match

  1. s[i] == 'I'时,使用可选择区间贪心 - 图29来构造
  2. s[i] == 'D'时,使用可选择区间贪心 - 图30来构造

重复以上过程,不断构造出子问题,贪心地求解出全局最优解。其中,可选择区间双指针来维护。

class Solution:
    def diStringMatch(self, s: str) -> List[int]:
        res = []
        left, right = 0, len(s)

        for ch in s:
            if ch == 'I':
                res.append(left)
                left += 1
            elif ch == 'D':
                res.append(right)
                right -= 1

        return res + [left]
  • 时间复杂度:贪心 - 图31
  • 空间复杂度:贪心 - 图32,不计算答案数组