python强化20日 第三天

python强化20日(蓝桥日)

第三天 Leetcode 贪心算法,蓝桥样题,回溯

贪心


45 跳跃游戏2(贪心算法)

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

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

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

示例:

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

#45 跳跃游戏2(贪心算法)
class Solution:
    def jump(self, nums):
        step=0
        end=0
        max_bound=0
        for i in range(len(nums)-1):            #定义nums-1目的是为了如果输入只有一个数,则会跳过直接认为是0
            max_bound=max(max_bound,nums[i]+i)  #最大边界在随着遍历实时寻找最大边界
            if(i==end):                         #当i触碰到最大边界说明完成一次贪心
                step+=1
                end=max_bound                   #最大边界更新
        return step

main = Solution()
print(main.jump([0]))
  • 重点,流程:
    设定变量:步数,当前最大边界值,更新最大边界值
    遍历一遍,注意遍历到n-1,保证如果刚进遍历时边界值为1直接跳出
  • 总结:
    贪心算法可以归结为一类实时找边界值的问题

134 加油站(贪心算法)

在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i] 升。

你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。

如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -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 可为起始索引。
示例 2:

输入:
gas = [2,3,4]
cost = [3,4,3]

输出: -1

解释:
你不能从 0 号或 1 号加油站出发,因为没有足够的汽油可以让你行驶到下一个加油站。
我们从 2 号加油站出发,可以获得 4 升汽油。 此时油箱有 = 0 + 4 = 4 升汽油
开往 0 号加油站,此时油箱有 4 - 3 + 2 = 3 升汽油
开往 1 号加油站,此时油箱有 3 - 3 + 3 = 3 升汽油
你无法返回 2 号加油站,因为返程需要消耗 4 升汽油,但是你的油箱只有 3 升汽油。
因此,无论怎样,你都不可能绕环路行驶一周。

  • 官方解答
    定一个出发点,看看是否可以往下走,一直到油箱不足则无法往下走,则在这一点之前的任何一点作为起点都无法继续走,那么起点要更替到下一个
    #如果这一点到下一点能走,那么下一点起始的油大于0,则如果这一点能走到头,起点不可能为下一点
#134 加油站(贪心算法)(解答)
#官方解答
class Solution1:
    def canCompleteCircuit(self, gas, cost):
        """
        :type gas: List[int]
        :type cost: List[int]
        :rtype: int
        """
        n = len(gas)
        
        total_tank, curr_tank = 0, 0
        starting_station = 0
        for i in range(n):
            total_tank += gas[i] - cost[i]
            curr_tank += gas[i] - cost[i]
            # If one couldn't get here,
            if curr_tank < 0:           #定一个出发点,看看是否可以往下走,一直到油箱不足则无法往下走,则在这一点之前的任何一点作为起点都无法继续走,那么起点要更替到下一个
                                        #如果这一点到下一点能走,那么下一点起始的油大于0,则如果这一点能走到头,起点不可能为下一点
                # Pick up the next station as the starting one.
                starting_station = i + 1
                # Start with an empty tank.
                curr_tank = 0               
        
        return starting_station if total_tank >= 0 else -1
  • 解答2
    根据规则的做法,因为答案是唯一的,所以汽车进行一次循环后油箱剩余油量最小,所以通过从前向后找到最小的油箱剩余量即可找到出发点位置
class Solution2:
    def canCompleteCircuit(self, gas, cost):
        rest = 0
        oil_minvalue = 0
        record_point = -1
        for i in range(len(gas)):
            rest += gas[i] - cost[i]
            if rest < oil_minvalue:
                oil_minvalue = rest
                record_point = i
        return -1 if rest < 0 else record_point + 1
  • 自己解答,更贴近贪心
    更加接近贪心算法的思路
    如果要循环一圈,汽车需要屯够足够的油,则汽车把囤油路线走掉则最有可能到达
    关键点:从后往前遍历,如果有出现tun比原先大,则这一点出发肯定能先走屯油路线,否则一定走的存在开头消耗的路线
    自己写
class Solution3:
    def canCompleteCircuit(self, gas, cost):
        max_tun = gas[len(gas)-1]-cost[len(gas)-1]
        tun = 0
        start_point = len(gas)-1
        for i in range(len(gas)-1,-1,-1):
            tun += gas[i]-cost[i]
            if tun > max_tun:
                max_tun = tun
                start_point = i
        return start_point if tun>=0 else -1

main = Solution3()
print(main.canCompleteCircuit([3,1,1],[1,2,2]))

135 分发糖果

  • 左右两次遍历挑选最大值
class Solution:
    def candy(self, ratings):
        result_left = [1]*len(ratings)
        result_right = [1]*len(ratings)
        for i in range(len(ratings)-1):
            if ratings[i] < ratings[i+1]:
                result_right[i+1] = result_right[i]+1#保证右边大于左边时右边多1


        
        for i in range(len(ratings)-1,0,-1):    #保证左边大于右边时左边多1
            if ratings[i] < ratings[i-1]:
                result_left[i-1] = result_left[i]+1

        #此处取两次结果每一次的最大值,保证两个条件都满足的同时,每一个所用糖果最小
        result = [max(result_right[i],result_left[i]) for i in range(len(ratings))]
        return sum(result)
  • 不取最大值版
class Solution2:
    def candy(self, ratings):
        result = [1]*len(ratings)
        for i in range(len(ratings)-1):
            if ratings[i] < ratings[i+1]:
                result[i+1] = result[i]+1#保证右边大于左边时右边多1


        
        for i in range(len(ratings)-1,0,-1):    #保证左边大于右边时左边多1
            if ratings[i] < ratings[i-1] and result[i] >= result[i-1]:  #当左边大于右边且结果内容不满足左大于右时
                result[i-1] = result[i]+1

        return sum(result)
  • 去掉去最大的步骤,第二次外直接加一个判断(网络参考版Solution2)
class Solution3:
    def candy(self, ratings):
        length = len(ratings)
        ans = [1] * length
        for i in range(1, length):
            if ratings[i] > ratings[i - 1]:
                ans[i] = ans[i - 1] + 1 

        for i in range(length - 2, -1, -1):
            if ratings[i] > ratings[i + 1] and ans[i] <= ans[i + 1]:
                ans[i] = ans[i + 1] + 1

        return sum(ans)


     
main = Solution2()
print(main.candy([1,2,2]))

蓝桥杯样题


  • 样题1

样题1:矩形切割(结果填空题)

【问题描述】

小明有一些矩形的材料,他要从这些矩形材料中切割出一些正方形。

当他面对一块矩形材料时,他总是从中间切割一刀,切出一块最大的正方形,剩下一块矩形,然后再切割剩下的矩形材料,直到全部切为正方形为止。

例如,对于一块两边分别为5和3的材料(记为5×3),小明会依次切出3×3、2×2、1×1、1×1共4个正方形。

现在小明有一块矩形的材料,两边长分别是2019和324。请问小明最终会切出多少个正方形?

【答案提交】

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

说明:以上是问题描述的部分,选手做题时可以直接手算答案,即按照题目意思一步一步切割,最后得到切出的矩形个数,手算可能花费一些时间。如果选手在手算时使用除法等方式加快速度,时间可能少一些。如果选手编写程序来计算,可以减少手算中出现的失误。

本题答案为:21

填空切正方形 程序(自己)

使用简单的递归

 #蓝桥杯样题
#切出多少,不是切多少次
def main(num1,num2,i):
    if num1 == num2:
        print(i)
        return
    num1_n = max(num1,num2)
    num2_n = min(num1,num2)
    num1_n = num1_n - num2_n
    main(num1_n,num2_n,i+1)

a = input().split(' ')
chang = int(a[0])
kuan = int(a[1])
main(chang,kuan,1)
  • 样题2:特别数的和(编程大题)

【问题描述】

小明对数位中含有2、0、1、9的数字很感兴趣(不包括前导0),在1到40中这样的数包括1、2、9、10至32、39和40,共28个,他们的和是574。

请问,在 1 到 n 中,所有这样的数的和是多少?

【输入格式】

输入一行包含一个整数 n。

【输出格式】

输出一行,包含一个整数,表示满足条件的数的和。

【样例输入】

40

【样例输出】

574

【评测用例规模与约定】

对于20%的评测用例,1≤n≤10。

对于50%的评测用例,1≤n≤100。

对于80%的评测用例,1≤n≤1000。

对于所有评测用例,1≤n≤10000。

说明:本题是一道编程题,选手需要编写一个程序来解决问题。以下给出一个参考程序,选手所编写的其他程序只要能给出正确的结果即可得分。

官方答案
n = int(input())
ans = 0
for i in range(1,n+1):
    t = i
    ok = False
    while t>0:
        g = t % 10
        if g==2 or g==0 or g==1 or g==9:
            ok = True
        t = t // 10
    if ok:
        ans += i
print(ans)
程序(自己)

想到了把数字转化成集合形式,然后取个交集看看交集存不存在

#蓝桥杯样题
#1到n含有2、0、1、9的数字
def main(num):
    result = 0
    for i in range(1,num+1):
        if len(set(list(str(i))) & set(['2','0','1','9']))!=0:
            result+=i
    print(result)


num = int(input())
main(num)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值