荷兰国旗问题

算法 专栏收录该内容
6 篇文章 0 订阅

 

上方的图片便是一个荷兰国旗,从图中我们可以很清楚的看出它的特点,它有三个区域组成,即红,白,蓝。

好,现在我们的问题出来了。现在我们面前有一张桌子,桌子上整齐的摆放着红色,白色,蓝色三种线条,但他们的顺序是凌乱的。

我们的要求是:用一个算法把这些线条挑出来重新摆放顺序,最后的结果就像上图的荷兰国旗,红色在上,白色在中间,蓝色在最下面。

 好了,我们该如何实现上面的问题呢?其实拿到这个问题每个人心中肯定都会有了一个算法,即:

①: 用一个变量标识我们要放的数组(用数组模拟桌子)的位置,初始化为0,然后依次递增。我们只需遍历整个数组,找红色的线条(红白蓝线条我们可以用0,1,2模拟),找到就把它和标识位置的线条进行交换。当标识之后的数组中没有红色线条时就找白色线条,白色线条找完之后,剩下的肯定就是蓝色的线条了。到此我们整个的算法就结束了。

我们看一下这个算法:

很容易被人想到的一种算法,但也是很复杂的一种算法,我们可以看出他的时间复杂度是O(N*M);

确实这样的算法在速度上很不容易被人接受。我们看一下另外一种算法:

②:我们首先将整个数组分为3个区域,即红色区域,白色区域,蓝色区域,然后首先我们遍历红色区域判断当前单元的值是否是红色,若是继续遍历,否则判断该值是白色还是蓝色,若是白色便去白色区域去寻找一个红色的单元与之交换,反之便去蓝色区域寻找一个值与之交换。当红色区域遍历完成之后,我们接着遍历白色区域,若当前单元不是白色,那肯定是蓝色了,我们便去蓝色的区域去寻找一个值与之交换。当蓝色区域遍历完成之后。我们的工作就完成了。

我们看下代码:

这种方法有个缺陷,不知道大家发现了没有。它少处理了一种情形,即:若是白色区域没有红色或是蓝色区域没有红色,算法没有对这种情况进行处理,应该若是在其中一种区域中没有找到,便去另一种区域中去找。

这种方法,若是在一般情况下它比第一种算法快了很多,因为它少了很多无谓的交换,出去上面遗漏的那种特殊情况,它的每次交换都是必要的交换。但是这种算法的时间复杂度还是有点高,应该仍是O(M*N);

我们分析一下上面的算法,我们交换之前都需要遍历数组的一部分进行寻找。这方面便浪费了时间,影响了我们的速度。我们可以来一个空间换时间的方法。我们再看另一个算法。

③: 我们首先定义三个数组来保存白色区域的红色部分位置,蓝色区域的红色部分和蓝色区域的白色部分位置。然后分别定义三个变量来标识这三个数组交换到的位置。算法之初我们便开始遍历白色区域,蓝色区域为这三个数组赋值。之后,我们便可以按照上面的方法依次遍历红色区域和白色区域了,找到之后只需和相应的数组中的位置与之交换就OK了。

我们看一下算法:

我们看一下这个算法的复杂度已为O(N)了;呵呵。不过我们为此耗费了一定的空间资源。用空间来换取了效率。当然还有其他更好的方法,当我相信复杂度为O(N)已经是最快的了。但我相信还有更简单的算法。只要我们肯于思考,奇迹总会出现呵呵。。

  • 0
    点赞
  • 4
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

评论 4 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

Joe_IceWind

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值