洛谷P1803 Java解法

题目出处点这里
在这里插入图片描述
思路:先把结束时间end从小到大排序,再按end时间从小到大参加比赛
约束条件:
1、前一个参加的比赛的end时间必须小于等于后一个参加比赛的start时间
2、前一个参加比赛的end时间必须小于后一个参加的比赛end时间

代码(解法一)如下:

两个判断的先后顺序略微会影响运行时间
可能是因为洛谷的测试数据的end时间没有重复的
所以在洛谷里把第二个约束条件注释掉也可以
后面还有解法二,我觉得对数据量大且end重复较多时的测试数据起到比较好的效果,
但在洛谷测试数据会很慢
package greedy;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Scanner;

public class P1803_plus {
	static ArrayList<time> list = new ArrayList<time>();// 存放time的队列
	static int sum = 0;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		// 存放time对象,同时把end的个数++
		for (int i = 0; i < n; i++) {
			list.add(new time(sc.nextInt(), sc.nextInt()));
		}
		// 按照end升序排列
		Collections.sort(list, new Comparator<time>() {
			public int compare(time a, time b) {
				return a.end - b.end;// 代表升序
			}
		});
		// 默认参加了排序后的第一个比赛(因为对于第一个参加的比赛来说,只要end相等,参加哪一个都无所谓),所以后面的i从1开始判断,好写代码
		sum = 1;
		// 用来记录上一个参加的比赛的索引,默认就是第一个比赛(因为已经排序好)
		int theLast = 0;
		for (int i = 1; i < n; i++) {// i从1开始,好写代码
			if (list.get(i).start >= list.get(theLast).end) {// 其次现在的start必须大于等于上一个比赛的end
				if (list.get(i).end > list.get(theLast).end) {// 首先现在的end必须大于上一个参加的比赛的end,否则会造成重复
					sum++;// 以上两个条件都满足的话.就++
					theLast = i;// 记得把上一个参加的比赛的索引变成现在已经参加过了的比赛i
				}
			}
		}
		System.out.println(sum);
	}
}

class time {
	int start;
	int end;

	public time(int start, int end) {
		this.start = start;
		this.end = end;
	}
}

代码(解法二):

此解法适用于数据量比较大且end重复较多的情况
思路:
1、用endCount[]记录每个end的个数,并把end的种类从大到小存放到endType[]2、这样就只需要经过endType.length次大循环
3、每次大循环把不同种类的end遍历一遍,只要这一次的start大于等于上一次的end,就次数++break
4、这种方法大大减少了解法一面对大量重复end时所需要的判断时间,因为在end重复量多即end种类少
  的时候需要经过的大循环就很少,每次大循环需要判断的次数也很少,因此此解法适用于数据量比较大
  且end重复较多的情况
5、但是在数据量大且end几乎不重复的情况下此解法时间会比较长,因为每次都需要找到不同end种类的
  索引范围,浪费了大量的时间并且需要经过的大循环的次数几乎就等于n,因此此解法不适用与数据量
  大且end几乎不重复的情况
package greedy;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Scanner;

public class P1803 {

	static ArrayList<time> list = new ArrayList<time>();//存放time的队列
	static ArrayList<Integer> endList = new ArrayList<Integer>();//存放end的队列
	static int[] endCount = new int[1000001];// 存放各个end分别出现的次数
	static ArrayList<Integer> endType = new ArrayList<Integer>(); // 存放存在的end类型
	static int index = 0;
	static int sum;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		// 存放time对象,同时把end的个数++
		for (int i = 0; i < n; i++) {
			int start = sc.nextInt();
			int end = sc.nextInt();
			list.add(new time(start, end));
			endList.add(end);
			endCount[end]++;
		}
		// 找出存在的end类型s
		for (int i = 0; i < endCount.length; i++) {
			if (endCount[i] > 0) {// 如果end类的数量大于0,就说明存在此类型
				endType.add(i);// 然后把i加进去即可
			}
		}
		// 按照end升序排列
		Collections.sort(list, new Comparator<time>() {
			public int compare(time a, time b) {
				return a.end - b.end;// 代表升序
			}
		});
		Collections.sort(endList);//对endList也进行升序排列
		// 排序完后先+1,代表已经选择了第一种end
		sum++;	
		//theLast代表上一个可以参加的比赛的end在endType中的索引
		int theLast = 0;	
		// 取出第二种end类型,如果此种end对应的start有 大于等于 第一种end的就+1
		int startIndex = 0;
		int endIndex = 0;
		for (int i = 1; i < endType.size(); i++) {
			startIndex = endList.indexOf(endType.get(i));
			endIndex = endList.lastIndexOf(endType.get(i));
			for (int j = startIndex; j <= endIndex; j++) {
				if (list.get(j).start >= endType.get(theLast)) {
					theLast = i;
					sum++;
					break;
				}
			}
		}
		System.out.println(sum);
	}
}

class time {
	int start;
	int end;

	public time(int start, int end) {
		this.start = start;
		this.end = end;
	}	
}

猜你喜欢

转载自blog.csdn.net/TXXERIN/article/details/107305350
今日推荐