[Leetcode] [Tutorial] Greedy


121. Best time to buy and sell stocks

Given an array prices, its i-th element prices[i] represents the price of a given stock on day i.

You can only choose to buy the stock on one day and sell the stock on a different day in the future. Design an algorithm to calculate the maximum profit you can make.

Returns the maximum profit you can make from this trade. If you cannot make any profit, return 0.

Example:
Input: [7,1,5,3,6,4]
Output: 5

Solution

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        start, end = 0, 0
        profit = 0
        for i in range(len(prices)):
            if prices[i] <= prices[start]:
                start = i
                end = i
            if prices[i] >= prices[end]:
                end = i
                profit = max(profit, prices[end] - prices[start])

        return profit

55. Jumping Game

Given an array nums of non-negative integers, you are initially at the first index of the array. Each element in the array represents the maximum length you can jump at that position.

Determine whether you can reach the last subscript, if so, return true; otherwise, return false.

Example:
Input: nums = [2,3,1,1,4]
Output: true

Solution

In a greedy algorithm, you don't care about whether you can get to the last index exactly, but you care about the farthest distance you can go. You increase the maximum reachable distance as much as possible at each step, and keep checking whether this maximum distance has covered the entire array.

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        max_reach = 0
        for i in range(len(nums)):
            if i > max_reach:
                return False
            max_reach = max(max_reach, nums[i] + i)
        return True

Of course, this problem can also be solved using the backtracking method.

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        return self.jump(nums, 0)

    def jump(self, nums: List[int], curr: int) -> bool:
        if curr >= len(nums) - 1:
            return True

        # 最多可以跳跃的长度
        max_jump = nums[curr]

        # 尝试从1到max_jump的所有跳跃长度
        for jump in range(max_jump, 0, -1):
            if self.jump(nums, curr + jump):
                return True

        return False

45. Jump Game II

Given a 0-indexed integer array nums of length n. The initial position is nums[0].

Each element nums[i] represents the maximum length of jump forward from index i. In other words, if you are at nums[i], you can jump to any nums[i + j]:

  • 0 <= j <= nums[i]
  • i + j < n

Returns the minimum number of hops to reach nums[n - 1]. The generated test cases can reach nums[n - 1].

Example:
Input: nums = [2,3,1,1,4]
Output: 2

Solution

Our goal is to find the index that maximizes the next max_reach within the current jump range.

class Solution:
    def jump(self, nums: List[int]) -> int:
        n = len(nums)
        if n < 2: return 0 # 当只有一个元素时,无需跳跃

        max_reach = 0
        jumps = 0
        i = 0
        while i < n:
            max_reach = i + nums[i]
            jumps += 1

            max_reach_temp = max_reach
            for j in range(i + 1, min(max_reach, n - 1) + 1):              
                if j + nums[j] > max_reach_temp:
                    max_reach_temp = j + nums[j]
                    i = j
            if max_reach >= n - 1:
                break
        return jumps

Since the goal is to reach the end in as few jumps as possible, the number of jumps must increase when entering a new jump range, so jumps += 1.

But we hope that the current jump can reach the farthest position that can be jumped in the next step, so as to minimize the total number of jumps. In order to achieve this, we need to check every position within the current jump range and find a position from which the maximum distance can be jumped.

763. Divide letter intervals

You are given a string s. We need to divide this string into as many segments as possible, and the same letter appears in at most one segment.

Note that the division results need to satisfy: all division results are connected in order, and the resulting string is still s.

Returns a list representing the length of each string fragment.

Example 1:
Input: s = "ababcbacadefegdehijhklij"
Output: [9,7,8]
Explanation:
The division results are "ababcbaca", "defegde", "hijhklij".
Each letter appears in at most one fragment.
Divisions like "ababcbacadefegde", "hijhklij" are wrong because the number of divided fragments is small.

Example 2:
Input: s = "eccbbbbdec"
Output: [10]

Solution

class Solution:
    def partitionLabels(self, s: str) -> List[int]:
        # 第一次遍历,记录每个字符最后出现的位置
        last = {
    
    char: idx for idx, char in enumerate(s)}

        # 初始化
        start = 0
        end = 0
        ans = []

        # 第二次遍历
        for idx, char in enumerate(s):
            # 考虑当前字符的最后出现位置,更新片段的结束位置
            end = max(end, last[char])

            # 当到达当前片段的结束位置时
            if idx == end:
                # 将当前片段加入结果列表中
                ans.append(end - start + 1)
                # 更新开始位置
                start = idx + 1

        return ans

Guess you like

Origin blog.csdn.net/weixin_45427144/article/details/132218419