2022-01-22 每日打卡:难题精刷

2022-01-22 每日打卡:难题精刷

写在前面

“这些事儿在熟练之后,也许就像喝口水一样平淡,但却能给初学者带来巨大的快乐,我一直觉得,能否始终保持如初学者般的热情、专注,决定了在做某件事时能走多远,能做多好。” 该系列文章由python编写,所刷题目共三个来源:之前没做出来的 ;Leetcode中等,困难难度题目; 周赛题目;某个专题的经典题目,所有代码已AC。每日1-3道,随缘剖析,希望风雨无阻,作为勉励自己坚持刷题的记录。

跳石头

2022-01-22 每日打卡:难题精刷_第1张图片

二分法用于解决不断逼近【最优解】的问题,往往是【尽可能大/小的最小/大解】问题。

check函数:

  • 目的往往是【指导】【最终答案】的走向,比如该题中,最终要求的是【尽可能大的最小距离】。那check函数的最终返回值的意义就是【当前尽可能大的最小距离】是偏大 or 偏小,换句话说就是当前距离是否满足条件
  • 往往将满足条件的情况放在True的条件下,返回True时不断逼近边界,也就是【尽可能】的部分 。此时在二分法中将【尽可能大/小】的一方边界放在True下,满足条件,使之靠近尽可能部分

二分的边界问题:

  • 进入条件:使用【最小值-1】和【最大值+1】即可,此时因为答案取不到边界,退出时无须取等于
  • 移动条件:此时必须使用 left/right = med 来保证等于的情况不被舍弃,注意此时的【退出条件】必须扩大差值为1,否则陷入死循环,二分法中只有【med一定不是最终解的时候】可以使用 left/right = med+-1
  • 退出条件:根据能否【能否逼近最优解】和【退出循环】两方面来决定的,而【能否逼近最优解】却决于第一条进入条件,【退出循环】取决于第二条移动条件
l, n, m = [int(_) for _ in input().split()]
rock = []
for _ in range(n):
    rock.append(int(input()))


def check(dis):
    tmp, mov = 0, 0
    for nxt in rock:
        if tmp + dis > nxt:
            mov += 1
        # 隐含条件:玩家可以跳的最大距离不限制
        else:
            tmp = nxt
    # 最短距离跳得到终点
    # 需要距离再变小一点,check不通过
    if tmp + dis > l:
        return False
    return mov <= m


try:
    # 答案介于0和(l//(n-m))+1之间
    left, right = 0, (l//(n-m))+1
    # 且取不到(l//(n-m))+1,所以不加等号
    # 之所以使用right-1,因为后面使用left/right=med
    # 防止出现left=4,med=4,right=5,check=True的不断循环
    while left < right-1:
        med = (left+right)//2
        # 返回正值,拿的偏少,距离可以更大
        # 倾向于取更大的距离,所以等于的情况我们也向后继续取直到不满足
        # 之所以不是med+-1的原因在于存在 [等于的情况就是边界]
        if check(med):
            left = med
        else:
            right = med

    # 退出时的left就是最终的结果
    # 因为等于的情况算在了left中
    print(left)

except:
    print(l)

你可能感兴趣的:(algorithm,算法,leetcode,职场和发展)