阿里巴巴2018秋招在线编程测验--射击场

阿里巴巴2018秋招在线编程测验:
 * 题目:假设靶场有n个靶子,n个靶子的分数为数组score[n],score[i]为0的靶子不能射击。
 * 射中第i个靶子的,假如第i个靶子的左右两边均有相邻靶子,则射中第i个靶的得分为score[left]*score[i]*score[right]
 * ,并且射中之后,score[left]和score[right]变为相邻的两个靶子。
 * 当射中的靶子右边没有相邻的靶子则得分为score[left]*score[i];左边同理。
 * 若左右两边均没有靶子,则得分为score[i]

 * 求最多能得多少分?

/**
 * @author yangs
 *
 *思路。
 *1、每次查找最佳的打靶点,进行打靶,累加此次打靶所获得的分数,打靶之后把该靶分数标位-1
 *2、查找最佳的打靶点策略:
 *  (1)首先查询中间所有可打靶(即未打过的靶score不为0的点)点(因为中间位置可以获得两次乘法,如果首先打去两端的靶子,那么将可能减少一次称的机会;计算得分不为0的位置),
 *  (2)再在所有候选打靶点选择score最小的打靶(选score最小的可以让大的score有相乘的机会多一些,从而总分数高)。
 *   (3) 若有打靶位置i,则进行打靶,并计算本次打靶所得分数,累加到总分,最后标记 score[i]=-1,跳转回执行第(1)步;否则进行到第(4)步。
 *  (4)如果在中间位置查询不到打靶位置,那么查找从两端可打靶位置。若也为找不到合法的打靶位置,说明打靶可以结束了,循坏break;否则返回执行第(3)步。
 *3、示例:2 4 5 6 3 2; 
 *    第1次打靶:2 4 5 6 3 2 最佳打靶位3,得分36,
 *    第2次打靶:2 4 5 6 2   最佳打靶位4,得分40,
 *    第3次打靶:2 5 6 2     最佳打靶位5,得分60,
 *    第4次打靶:2 6 2       最佳打靶位6,得分24,
 *    第5次打靶:2 2         最佳打靶位2,得分4 
 *    第6次打靶:2           最佳打靶位2,得分2,
 *    总分得:36+40+60+24+4+2=166)。
 * 示例:2 4 5 0 3 2;
 *  第1次打靶:2 4 5 0 3 2 最佳打靶位4,得分40,
 *  第2次打靶:2 5 0 3 2   最佳打靶位2,得分10,(中间已经找不到打靶位置,打去两端的)
 *  第3次打靶:5 0 3 2     最佳打靶位2,得分6,
 *  第3次打靶: 5 0 3 找不到打靶位置,循坏结束。
 *  总分得40+10+6=56。
 * 
 */
public class Main {
	public int deal(int []score) {
		int n=score.length;
		int sum=0;
		for(int j=0;j<n;j++)
		{
			int k=find(score,1,n-1);
			if(k==-1&&(k=find(score,0,n))==-1)break;
			int grade=score[k];//当前靶点得分
			if(k>0){
				int l=k-1;
				while(l>=0&&score[l]==-1)l--;
				if(l>=0){//如果左边存在没打过的靶
					//如果左边的靶分数不为0
					if(score[l]>0)grade*=score[l];
					else continue;//左边的靶分数为结束本次当前循坏
				}
			}
			if(k+1<n){
				int l=k+1;
				while(l<n&&score[l]==-1)l++;
				if(l<n){//如果右边边存在没打过的靶
					if(score[l]>0)grade*=score[l];
					else continue;
				}
			}
			sum+=grade;
			score[k]=-1;
		}
		return sum;
	}
	/**
	 * 查找最佳打靶点
	 * @param score 
	 * @param j 查找起始位置
	 * @param i 查找结束位置
	 * @return bestIndex 最佳打靶位置
	 */
	private int find(int[] score, int j,int i) {
		int min=Integer.MAX_VALUE;
		int bestIndex=-1;
		for(;j<i;j++){
			//如果当前点score为0或-1,则跳过该点
			if(score[j]<=0)continue;
			if(j>0){
				int k=j-1;//找出左边相邻的靶
				while(k>=0&&score[k]==-1)k--;
				//如果左边相邻的靶为0,则当前靶点无效,打了也是0分,结束本次当前循坏
				if(k>=0&&score[k]==0)continue;
			}
			if(j+1<i){
				int k=j+1;//找出右边相邻的靶
				while(k<i&&score[k]==-1)k++;
				//如果右边相邻的靶为0,则当前靶点无效,打了也是0分,结束本次当前循坏
				if(k<i&&score[k]==0)continue;
			}
			//候选靶点中取较小的靶点
			if(min>score[j]){
				min=score[j];
				bestIndex=j;
			}
		}
		return bestIndex;
	}
}
求教大家,有没有好一点的算法

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值