按权重给小孩分糖果,笔试题。

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;
	}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值