贪心算法
一 ·基本概念
所谓贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择。必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性,即某个状态以后的过程不会影响以前的状态,只与当前状态有关。所以对所采用的贪心策略一定要仔细分析其是否满足无后效性。
二 ·贪心算法的基本思路
1.建立数学模型来描述问题。
2.把求解的问题分成若干个子问题。
3.对每一子问题求解,得到子问题的局部最优解。
4.把子问题的解局部最优解合成原来解问题的一个解。
三 ·贪心算法的使用条件
1、贪心选择性质
一个问题的整体最优解可通过一系列局部的最优解的选择达到,并且每次的选择可以依赖以前作出的选择,但不依赖于后面要作出的选择。这就是贪心选择性质。对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所作的贪心选择最终导致问题的整体最优解。
2、最优子结构性质
当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。问题的最优子结构性质是该问题可用贪心法求解的关键所在。在实际应用中,至于什么问题具有什么样的贪心选择性质是不确定的,需要具体问题具体分析。
四 ·例题
假设有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花不能种植在相邻的地块上,它们会争夺水源,两者都会死去。
给你一个整数数组 flowerbed 表示花坛,由若干 0 和 1 组成,其中 0 表示没种植花,1 表示种植了花。另有一个数 n ,能否在不打破种植规则的情况下种入 n 朵花?能则返回 true ,不能则返回 false。
输入:flowerbed = [1,0,0,0,1], n = 1
输出:true
解题思路:这道题是如果有连续的三个0,那么中间的位置就可以种花,此时要将该位置的元素赋值为1。除此之外,还有两个容易忽视的地方,第一个位置和最后一个位置,如果第一个位置为0,那么该位置就可以种花。倒数第二个位置为0并且最后一个位置也为0,那么最后一个位置也可以种花。如果可以种花的位置大于等于所给的数目,返回true,否则返回false。
这是第一次做出的答案,不但没有考虑到第一个位置,而且超出了时间限制
bool canPlaceFlowers(int* flowerbed, int flowerbedSize, int n){
int i,cnt=0;
for(i=0;i<flowerbedSize-1;i++)
{
while(flowerbed[i]==0)
{
if(flowerbed[i-1]==0 &&flowerbed[i+1]==0)
{
flowerbed[i]=1;
cnt++;
}
}
}
if(flowerbed[flowerbedSize-1]==0 && flowerbed[flowerbedSize-2]==0)
{
cnt++;
}
if(cnt<n)
{
return false;
}
else
{
return true;
}
}
当n为0时,返回的总是true,这是修改后的代码:
bool canPlaceFlowers(int* flowerbed, int flowerbedSize, int n){
int i;
if(n==0)
{
return true;
}
for(i=0;i<flowerbedSize;i++)
{
if(flowerbed[i]==0 && (i==0 ||flowerbed[i-1]==0) &&(i==flowerbedSize-1 || flowerbed[i+1]==0))
{
n--;
if(n<=0)
{
return true;
}
flowerbed[i]=1;
}
}
return false;
}