(二)算法基础:模拟

一.简介

模拟就是用计算机来模拟题目中要求的操作。

模拟题目通常具有码量大、操作多、思路繁复的特点。由于它码量大,经常会出现难以查错的情况,如果在考试中写错是相当浪费时间的。

二.技巧

写模拟题时,遵循以下的建议有可能会提升做题速度:

  • 在动手写代码之前,在草纸上尽可能地写好要实现的流程。
  • 在代码中,尽量把每个部分模块化,写成函数、结构体或类。
  • 对于一些可能重复用到的概念,可以统一转化,方便处理:如,某题给你 "YY-MM-DD 时:分" 把它抽取到一个函数,处理成秒,会减少概念混淆。
  • 调试时分块调试。模块化的好处就是可以方便的单独调某一部分。
  • 写代码的时候一定要思路清晰,不要想到什么写什么,要按照落在纸上的步骤写。

实际上,上述步骤在解决其它类型的题目时也是很有帮助的。

三.例题

题目一:

一只长度不计的蠕虫位于n英寸深的井的底部。它每次向上爬u英寸,但是必须休息一次才能再次向上爬。在休息的时候,它滑落了d英寸。之后它将重复向上爬和休息的过程。蠕虫爬出井口需要至少爬多少次?如果蠕虫爬完后刚好到达井的顶部,我们也设作蠕虫已经爬出井口。 

 解题分析:

我们只需要编写程序,模拟蠕虫的爬行,根据题目要求添加结束条件即可得到问题的解。n为蠕虫需爬行的总距离,我们可以设置一个循环模拟蠕虫爬行,循环每次先爬行u,使得剩余距离-u,再滑落d,即剩余距离+d。爬行结束只会发生在u过程中,当爬行u过程中或结束时,剩余距离0(即总爬行距离达到n)则完成了爬行。

# Python
u, d, n = map(int, input().split())
time = dist = 0
while True:  # 用死循环来枚举
    dist += u
    time += 1
    if dist >= n:  # 满足条件则退出死循环
        break
    dist -= d
print(time)  # 输出得到的结果

题目二:

给定一个整数数组 asteroids,表示在同一行的行星。

对于数组中的每一个元素,其绝对值表示行星的大小,正负表示行星的移动方向(正表示向右移动,负表示向左移动)。每一颗行星以相同的速度移动。

找出碰撞后剩下的所有行星。碰撞规则:两个行星相互碰撞,较小的行星会爆炸。如果两颗行星大小相同,则两颗行星都会爆炸。两颗移动方向相同的行星,永远不会发生碰撞。

示例 1:

输入:asteroids = [5,10,-5]
输出:[5,10]
解释:10 和 -5 碰撞后只剩下 10 。 5 和 10 永远不会发生碰撞。


示例 2:

输入:asteroids = [8,-8]
输出:[]
解释:8 和 -8 碰撞后,两者都发生爆炸。


示例 3:

输入:asteroids = [10,2,-5]
输出:[10]
解释:2 和 -5 发生碰撞后剩下 -5 。10 和 -5 发生碰撞后剩下 10 。

解题思路:

这里我们模拟行星的运动,首先我们容易得到以下结论

  • 同向移动行星无法发生碰撞
  • 异向行星可能发生碰撞,必须正行星在左,负行星在右。

易推,只有右边的负行星会与左边的正行星发生碰撞这一种碰撞情况

我们从左至右遍历行星,也相当于视线向右运动,所以我们以向右运动的正数行星为参考。用一个栈记录视线遍历过发生碰撞后剩余的行星

当遍历到正的行星(方向向右),一定不会和栈中行星发生碰撞,我们将这颗行星加入栈中:因为行星向右,首先不可能与栈中负行星碰撞,因为负行星在左边向左移动,对于栈正行星也不会发生碰撞,因为行星移动速度一致,同向行星无法追上彼此碰撞 

当遍历到负行星时分情况进行碰撞判断讨论:

  • 当栈中没有行星时,不满足右负左正的碰撞条件,直接将负行星加入栈,结束碰撞判断
  • 当栈顶(最右侧)是负行星时,不满足右负左正碰撞条件,可直接将负行星入栈,结束碰撞判断
  • 当栈顶是正行星时,满足碰条件,发生碰撞。1.如果正行星体积大,该负行星爆炸,不执行任何操作,结束碰撞判断;2.如果负行星体积大,取出栈顶正行星(相当于该行星爆炸),继续进行该负行星的下一轮碰撞判断;3.行星体积相等,取出栈顶正行星,结束碰撞判断

在代码中,我们用一个变量alive记录该负行星是否需要入栈

class Solution:
    def asteroidCollision(self, asteroids: List[int]) -> List[int]:
        stars = []
        for i in asteroids:
            if i > 0:
                stars.append(i)
            else:
                alive = True
                while stars:
                    right = stars.pop()
                    if right < 0:
                        stars.append(right)
                        break
                    else:
                        if right > abs(i):
                            stars.append(right)
                            alive = False
                            break
                        elif right + i == 0:
                            alive = False
                            break
                if alive:
                    stars.append(i)
        return stars

你可能感兴趣的:(算法学习,算法)