PAT甲级1044 Shopping in Mars(JAVA版)

31 篇文章 0 订阅

本题简单解析

考察所谓的“二分查找”,但我使用JAVA实现二分查找的方法,AC时竟然比先前自己写的代码通过的测试点还少。
以下是代码运行时间的比较:
测试用例(PAT标准用例1):

16 15
3 2 1 5 4 6 8 7 16 10 15 11 9 12 14 13
版本运行时间测试用例未通过的序号
自己写的版本15295904300ns2,4,5
自己写的版本21823066099ns2,4,5
根据柳神博客写的二分查找版本4099952500ns1,2,3,4,5

自己的版本1与版本2区别在于进入循环时判断某一值是否已经大于最小值,若是则跳过该循环。

自己写的版本的思路

很简单,每读入一个数字,把该数字分别与先前的数组内元素加和,并将该数字存到对应位置。
以PAT标准用例1为例

16 15
3 2 1 5 4 6 8 7 16 10 15 11 9 12 14 13
第一次读取后数组:
3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
第二次读取后数组:
5 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0
第三次读取后数组:
6 3 1 0 0 0 0 0 0 0 0 0 0 0 0 0
......

按照如上思路该数组第一个元素代表从第一个钻石开始叠加的价值,第二个元素代表从第二个钻石开始叠加的价值…
并设置mincost变量代表最小的钻石价值支出。

二分查找的思路

:将每个钻石的价值按照顺序逐次叠加,从题目给定第一个钻石开始,设每次循环取到的钻石为Z,且注意(第一次循环设该循环取到的钻石价值为0,第二次循环取到题目给定钻石串的第一个)每次循环找到一个符合“Z作为本次循环结果钻石串的第一个且该结果钻石串总价值大于等于且最接近题目给定所要支付的价值的钻石串,然后根据该循环结果与最小价值、题目给定所要求支付的价值进行比较,从而得到结果。

版本1、2代码

版本2就是把下面代码里面的三行注释去掉注释符:

import java.util.ArrayList;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner scaner = new Scanner(System.in);
		int diamondsNum = scaner.nextInt();
		int totalMoney = scaner.nextInt();
		int[] diamondsString = new int[diamondsNum];
		boolean flag = false;
		ArrayList<Integer> start = new ArrayList<>();
		ArrayList<Integer> end = new ArrayList<>();
		int mincost = Integer.MAX_VALUE;
		int[] addValue = new int[diamondsNum];
		for(int i = 0 ; i < diamondsNum ; i++) {
			diamondsString[i] = scaner.nextInt();
			addValue[i] = 0;
			for(int j = i ; j >= 0 ; j--) {
				addValue[j] += diamondsString[i];
//				if(addValue[j] > mincost) {
//					break;
//				}
				if(addValue[j] == totalMoney) {
					flag = true;
					if((i + 1) > (j + 1))
						System.out.println((j + 1) + "-" + (i + 1));
					else
						System.out.println((i + 1) + "-" + (j + 1));
				}
				else if(addValue[j] > totalMoney) {
					if(addValue[j] < mincost) {
						mincost = addValue[j];
						start.clear();
						end.clear();
						start.add((i + 1));
						end.add((j + 1));
					}
					else if(addValue[j] == mincost) {
						start.add((i + 1));
						end.add((j + 1));
					}
					
				}
			}
		}
		scaner.close();
		if(!flag) {
			for(int i = 0 ; i < start.size() ; i++) {
				if(start.get(i) < end.get(i))
					System.out.println(start.get(i) + "-" + end.get(i));
				else
					System.out.println(end.get(i) + "-" + start.get(i));
				
			}
		}
	}

}

二分查找版本

根据柳神博客改写:

import java.util.ArrayList;
import java.util.Scanner;

public class Main {
	static int diamondsNum = -1;
	static int totalMoney = -1;
	static int[] diamondsString;
	
	static int[] binaryCheck(int start) {
		int[] result = new int[2];
		int left = start - 1;
		int leftValue;
		if(left == -1)
			leftValue = 0;
		else
			leftValue = diamondsString[left];
		int right = diamondsNum - 1;
		while(left < right) {
			int mid = (left + right)/2;
			if(diamondsString[mid] - leftValue >= totalMoney)
				right = mid;
			else
				left = mid + 1;			
		}
		result[0] = right;
		result[1] = diamondsString[right] - leftValue;
		return result;
	}

	public static void main(String[] args) {
		Scanner scaner = new Scanner(System.in);
		diamondsNum = scaner.nextInt();
		totalMoney = scaner.nextInt();
		diamondsString = new int[diamondsNum];
		ArrayList<Integer> start = new ArrayList<>();
		ArrayList<Integer> end = new ArrayList<>();
		int mincost = Integer.MAX_VALUE;
		for(int i = 0 ; i < diamondsNum ; i++) {
			diamondsString[i] = scaner.nextInt();
			if(i >= 1)
				diamondsString[i] += diamondsString[i - 1];
		}
		scaner.close();
		for(int i = 0 ; i < diamondsString.length ; i++) {
			int[] temp = binaryCheck(i);
			int left = i;
			int right = temp[0];
			int tempSum = temp[1];
			if(tempSum >= totalMoney) {
				if(tempSum < mincost) {
					start.clear();
					end.clear();
					mincost = tempSum;
					start.add(left + 1);
					end.add(right + 1);
				}
				else if(tempSum == mincost) {
					start.add(left + 1);
					end.add(right + 1);
				}
			}
		}
		for(int i = 0 ; i < start.size() ; i++) {
			System.out.println(start.get(i) + "-" + end.get(i));
		}
		  
	}

}

分析

感觉可能是java天生运行速度就比不上c++,而且题目给的测试用例规模也挺大的。另外我该写柳神的代码可能也存在错误,导致改写的JAVA代码运行时间长,恳请看到这篇博客的各位大佬斧正,小弟不胜感激。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值