lettcode刷题之贪心

2023-01-03  本文已影响0人  sk邵楷

leetcode刷题,使用python

1, 跳跃游戏 II —— 0045 贪心算法
给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。
每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i + j] 处:
0 <= j <= nums[i]
i + j < n
返回到达 nums[n - 1] 的最小跳跃次数。生成的测试用例可以到达 nums[n - 1]。

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

from typing import List

class Solution:
    def jump(self, nums: List[int]) -> int:
        n = len(nums)
        maxPos, end, step = 0, 0, 0

        for i in range(n-1):
            if i<= maxPos:
                maxPos = max(maxPos, i+nums[i])

                if maxPos >= n-1:
                    return step+1

                if i == end:
                    end = maxPos
                    step += 1

        return step


S = Solution()
nums = [2,3,1,1,4]
#nums = [3,2,1,0,4]
print(S.jump(nums))

2, 加油站 —— 0134 贪心算法

在一条环路上有 n 个加油站,其中第 i 个加油站有汽油 gas[i] 升。
你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。
给定两个整数数组 gas 和 cost ,如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1 。如果存在解,则 保证 它是 唯一 的。

示例 1:

输入: gas = [1,2,3,4,5], cost = [3,4,5,1,2]
输出: 3
解释:
从 3 号加油站(索引为 3 处)出发,可获得 4 升汽油。此时油箱有 = 0 + 4 = 4 升汽油
开往 4 号加油站,此时油箱有 4 - 1 + 5 = 8 升汽油
开往 0 号加油站,此时油箱有 8 - 2 + 1 = 7 升汽油
开往 1 号加油站,此时油箱有 7 - 3 + 2 = 6 升汽油
开往 2 号加油站,此时油箱有 6 - 4 + 3 = 5 升汽油
开往 3 号加油站,你需要消耗 5 升汽油,正好足够你返回到 3 号加油站。
因此,3 可为起始索引。

from typing import List

#  贪心算法
class Solution:
    def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
        # 总油量 < 总耗油量,一定无解
        if sum(gas) < sum(cost):
            return -1

        # sum(gas) >= sum(cost),一定有解【题目保证唯一解】
        n = len(gas)
        start = 0 # 记录出发点,从索引0开始
        total = 0 # 记录汽车实际油量
        for i in range(n):
            total += gas[i] - cost[i]  # 每个站点加油量相当于 gas[i] - cost[i]
            if total < 0:   # 在i处的油量<0,说明从之前站点出发的车均无法到达i
                start = i+1 # 尝试从下一个站点i+1重新出发
                total = 0   # 重新出发时油量置为0

        return start

S = Solution()
gas = [1,2,3,4,5]
cost = [3,4,5,1,2]

print(S.canCompleteCircuit(gas, cost))

3, 最大数—— 0179 贪心算法
给定一组非负整数 nums,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。
注意:输出结果可能非常大,所以你需要返回一个字符串而不是整数。
示例 1:
输入:nums = [10,2]
输出:"210"

import  functools
from typing import  List

class Solution:
    def largestNumber(self, nums: List[int]) -> str:
        strs = map(str, nums)       #将数字映射成为字符

        def cmp(a, b):
            if a+b == b+a:
                return 0
            elif a+b > b+a:
                return 1
            else:
                return -1

        strs = sorted(strs, key=functools.cmp_to_key(cmp), reverse=True)
        return ''.join(strs) if strs[0] != '0' else '0'

S = Solution()
nums = [10,2]
print(S.largestNumber(nums))

4, 去重重复字母 —— 0316 贪心算法+单调栈
给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
示例 1:
输入:s = "bcabc"
输出:"abc"

import collections

class Solution:
    def removeDuplicateLetters(self, s: str) -> str:
        res = []
        # freq[c] 表示之后时间里每个字符会出现的次数 初始化为每个字母的频数 遍历过程中减小
        freq = collections.Counter(s)

        for c in s:
            #如果c不在res中, 再考虑是否添加
            if c not in res:
                while len(res)>0 and res[-1]>c and freq[res[-1]]>0:
                    res.pop()
                res.append(c)

            # 无论是否添加c 它之后出现的频数都-1
            freq[c] -= 1

        return ''.join(res)

S = Solution()
s = "bcabc"
print(S.removeDuplicateLetters(s))

5, 递增的三元子序列 —— 0334 贪心算法 或者 双向链表
给你一个整数数组 nums ,判断这个数组中是否存在长度为 3 的递增子序列。
如果存在这样的三元组下标 (i, j, k) 且满足 i < j < k ,使得 nums[i] < nums[j] < nums[k] ,返回 true ;否则,返回 false 。

示例 1:
输入:nums = [1,2,3,4,5]
输出:true
解释:任何 i < j < k 的三元组都满足题意

from typing import List


#贪心算法  感觉自己肯定想不出来
class Solution:
    def increasingTriplet(self, nums: List[int]) -> bool:
        n = len(nums)
        if n<3:
            return False

        first, second = nums[0], float('inf')

        for i in range(1, n):
            num = nums[i]
            if num > second:
                return True
            if num > first:
                second = num
            else:
                first = num

        return False


#双向链表
class Solution2:
    def increasingTriplet(self, nums: List[int]) -> bool:
        n = len(nums)
        if n<3:
            return False

        leftMin = [0] * n   # leftMin数组中 leftMin[i]表示 num[0]到nums[i]中的最小值
        leftMin[0] = nums[0]

        rightMax = [0] * n  # rightMax数组中 rightMax[i]表示 num[i]到nums[n-1]中的最大值
        rightMax[n-1] = nums[n-1]

        for i in range(1, n):
            leftMin[i] = min(leftMin[i-1], nums[i])

        for i in range(n-2, -1, -1):
            rightMax[i] = max(rightMax[i+1], nums[i])

        for i in range(1, n-1):
            if leftMin[i-1] < nums[i] < rightMax[i+1]:
                return True
        return False


nums = [1, 2, 3, 4, 5]
S = Solution()
S2 = Solution2()
print(S.increasingTriplet(nums))
print(S2.increasingTriplet(nums))

上一篇下一篇

猜你喜欢

热点阅读