2015/10/20
xxx最后一个笔试题:按权重给小孩分糖果。
N个孩子站成一排,给每个人设定一个权重(已知)。按照如下的规则分配糖果:
(1)每个孩子至少分得一颗糖果
(2)权重较高的孩子,会比他的邻居获得更多的糖果。
问:总共最少需要多少颗糖果?请分析算法思路,以及算法的时间,空间复杂度是多少。
如权重为:{1,3,2,1}
糖块为:1+3+2+1=7;
如权重为:{1,3,2,2}
糖块为:1+2+1+1=5;
n个权重(数组a中)不同的孩子随机排列,进行分配
1、每个孩子分配一个;b[i]表示第i个孩子的糖果数
2、假设前面i-1个已分配好,现在分配第i个孩子,
如果i权重较大,b[i]增加到比b[i-1]糖果多1,
如果i权重较小,且b[i-1]等于b[i],b[i-1]加1,然后i减1再进行循环
3、最后统计b[i]之和。
空间复杂度O(n),最坏情况下,时间复杂度O(n^2),最好情况下,时间复杂度O(n)。
int getMinCandys(int [] a,int n)
{
int count=0;
int [] b=new int[n];
if(n<2)
{
return 1;
}
//每个小孩预先分一颗糖
for(int i=0;i<n;i++)
{
b[i]=1;
}
//开始按权值分糖,位置i与i-1位置比较,i从1开始
for(int j=1;j<n;j++)
{
//权重i等于i-1 ,在原来基础上保持不变
if(a[j]==a[j-1])
{
b[j]=b[j]+b[j]-b[j-1];
}
//权重i大于i-1,在原来基础上b[j]比b[j-1]多1
if((a[j]>a[j-1]) && (b[j]<=b[j-1]))
{
b[j]=b[j]+b[j]-b[j-1]+1;
}
//权重i小于于i-1,在原来基础上b[j-1]多1,并且进行i--扫描
if((a[j]<a[j-1]) && (b[j]>=b[j-1]))
//if(a[j]<a[j-1])
{
b[j-1]=b[j-1]+1;
if(j>1)
{
j-=2; //因为for中要执行j++
}
}
}
for(int k=0;k<n;k++)
{
count+=b[k];
}
return count;
}
方法二:
1、先每人发一颗糖;
2、第一遍从前往后扫描,满足相邻两个小孩后面的权重大于前面的权重的情况,后面的小孩在前面的小孩的糖果数的基础上加一个。
3、第二遍从后往前扫描,满足条件与第一遍扫描一样。这样两遍扫描下来就可以保证权重高的孩子比相邻权重低的孩子的糖果多。
时间复杂度是O(n),空间复杂度是O(n)。
int getMinCandys(int [] a,int n)
{
int count=0;
int [] b=new int[n];
//只有一个小孩,直接返回1
if(n<2)
{
return 1;
}
//每个小孩预先分一颗糖
for(int i=0;i<n;i++)
{
b[i]=1;
}
int j;
//正扫描
for( j=1;j<n;j++)
{
//权重i大于i-1 ,比前一个多1
if(a[j]>a[j-1])
{
b[j]=b[j-1]+1;
}
}
//反扫描
for( j=n-1;j>1;j--)
{
//权重i小于i-1 ,i-1比i多1
if((a[j]<a[j-1])&&(b[j-1]<(b[j]+1)))
{
b[j-1]=b[j]+1;
}
}
for(int k=0;k<n;k++)
{
count+=b[k];
}
return count;
}