您的位置:首页 > 其它

继续贪心:删数问题

2016-05-17 23:27 218 查看
上次已经讲过一次贪心了,这次就来个小实战吧,下面看题:

**

删数问题

**

已知一个数组,要求从数组中删除n个数,要求剩下的数按顺序排列成的数字最小。例:数组为{1,3,2,4,7,0,5} n = 3; 输出结果为: 1 2 0 5

拿到题先分析,首先分析上面的例子试试吧,既然要删除n个数,那就一个一个删吧,那么删的时候要遵循什么标准呢?只要每次删的时候依次枚举删后的结果,挑选一个最小的就好了。因为每次删数都需要遍历当前数组里的有效值,需要删n个数,所以时间复杂度大概为O(n*len);但是,我们每次删除一个数时,都要将数组里的有效元素一一提取出来,合并成一个整数,才可以进行比较,这个合并的过程时间复杂度为O(len);当然,你可以直接按顺序从数组头部到尾部依次比较,这样可以优化一些,但是无法改变本质,最坏时间复杂度依然是O(len);这种方法也很简单,所以我就不讲这个算法了,下面提供另一种思路。

首先,我们学习贪心算法,其实并没有什么用,因为大部分人即使不学贪心算法也会有贪心的思想,而且算法本身只是思想,空有一身思想是没有任何用的,写出什么程序,完全是看自己如何思考的。

所以,我们的目的不只是如何贪心,而是如何尽可能的贪。

首先,从逻辑上讲,删数和选数是一样的。删n个数等价于选len-n个数。那么我们可以将删数转化成选数问题。那么我们根据什么标准来选数呢?是每次选最小的吗?就上面的例子说,如果要删除五个数,那就是选择两个数,结果很明显是 0 5,但是假如每次选最小的数,得到的结果是 1 0,是不正确的。所以可以排除每次选最小的方案,但是选择小的肯定不会错,分析发现,当第一次选择最小的数,这个数把数组分成两部分,下次选择时,只要这个最小的数后面还有数,那么一定优先选后面的数,当后面的数选完时,才选择前面的数。

那么看看逻辑吧:

数组中有len个数,需要选择n个数,我们先选择一个最小的,先假设这个最小的数的下标为i,那么还需要选择n-1个数,这n-1个数优先从最小的数的后面选,最小的数后面一共还有len-i个数,那么就有两种情况:

①:len-i > n-1 ;从最小的数后面的数里选择n-1个数;

②:len-i < n-1 ;选择最小的数后面的全部数,然后从最小的数前面选择n-1-len+i个数;

当然,这样做有个问题:因为是每次选择一个数,我们该如何记录选择的数的原顺序?

其实这个问题可以很好地用树的思想解决:

我们可以利用遍历树的方式,先计算最小的数之前的部分,然后输出最小的数,在计算最小的数之后的部分,使用递归实现,很简单的。

函数的简单结构如下:

delete()

{

delete(font); 计算最小的数之前的部分

put(min); 输出最小的数

delete(last); 计算最小的数之后的部分

}

//上面只是简单的逻辑,用C语言实现的话还得费些功夫,没什么难度,但是比较麻烦,最麻烦的是数组下标的控制,大家可以结合我的代码分析分析。

特殊情况:当你只需要删除0个数时,将原数组整个输出一遍就行了,不必继续往下递归了,这样可以节约很多时间。

下面放出我的代码:

#include <stdio.h>
#include <stdlib.h>

static int delete(int *, int, int);

static int low(int, int);

int main()
{
int a[] = {1,3,2,4,7,0,5};
// int a[] = {1,2,6,3,4};
int n = sizeof(a) / sizeof(a[0]);
delete(a,n,n-4);
return 0;
}

int delete(a,n,d)
int * a;
int n, d;
{
if (d <= 0)
return 0;
if (n == d)
{
for (int i = 0; i < n; i++)
printf("%4d",a[i]);
return n;
}
int min = 0;
for (int i = 1; i < n; i++)
{
if (a[i] < a[min])
min = i;
}
delete(a,min,d-n+min);
printf("%4d",a[min]);
delete(&a[min+1],n-min-1,low(n-min,d)-1);
return n;
}

int low(int x, int y)
{
return x<y?x:y;
}


贪心很简单,不如动规那样繁琐,所以到这里贪心算法基本上可以结了,希望大家多敲代码,多磨练自己。最近在给一个大一的学弟上C语言基础课,改天我会总结一下比较有意思的知识点,跟大家分享一下。

我是算法吹,以后会给大家带来更多精彩的算法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: