一、贪心算法
1、区间相关问题:选择不相交的区间
数轴上有n个开区间(begin,end),尽量选择数量最多的区间,使得这些区间两两没有交集。【某国王打算让将军们去守卫长城(可当做一条线段),每个人选择一个自己喜欢的区间段,为了让最多的将军能守卫自己想守卫的地方,怎么安排是最合理的呢?例如:长城的区间段是[1,1000],每个将军选择的区间段都在这个范围内,任意两个将军守卫的地方不能有重合的地方,否则会出现争执,两个点的交集不算交集】
比如输入:
1 2 324 2 320 424 3 259 342 4 371 888 5 264 634 6 909 982 7 117 653 8 677 929 9 656 707 10 297 915 11 904 943 12 309 564 13 564 601 14 675 876 15 33 89 16 363 912 17 226 952 18 86 129 19 216 339 20 258 857
则对应输出
第1个区间段为[33,89] 第2个区间段为[216,339] 第3个区间段为[564,601] 第4个区间段为[656,707] 第5个区间段为[904,943] 最多有5个区间段
解题思路:使用贪心算法,贪心策略为按照end从小到大的顺序将所有区间进行排序,每次取与之前的区间不相交的第一个区间
public class Changcheng implements Comparable<Changcheng>{ private int begin; private int end; public Changcheng(int begin, int end) { this.begin = begin; this.end = end; } public int getBegin() { return begin; } public void setBegin(int begin) { this.begin = begin; } public int getEnd() { return end; } public void setEnd(int end) { this.end = end; } @Override public int compareTo(Changcheng o) { if(this.getEnd() > o.getEnd()) { return 1; }else if(this.getEnd() < o.getEnd()) { return -1; } return 0; } }
import java.util.Arrays; public class Solution { public static void main(String[] args) { Changcheng[] changcheng = new Changcheng[20]; changcheng[0] = new Changcheng(2, 324); changcheng[1] = new Changcheng(320, 424); changcheng[2] = new Changcheng(259, 342); changcheng[3] = new Changcheng(371, 888); changcheng[4] = new Changcheng(264, 634); changcheng[5] = new Changcheng(909, 982); changcheng[6] = new Changcheng(117, 653); changcheng[7] = new Changcheng(677, 929); changcheng[8] = new Changcheng(656, 707); changcheng[9] = new Changcheng(297, 915); changcheng[10] = new Changcheng(904, 943); changcheng[11] = new Changcheng(309, 564); changcheng[12] = new Changcheng(564, 601); changcheng[13] = new Changcheng(675, 876); changcheng[14] = new Changcheng(33, 89); changcheng[15] = new Changcheng(363, 912); changcheng[16] = new Changcheng(226, 952); changcheng[17] = new Changcheng(86, 129); changcheng[18] = new Changcheng(216, 339); changcheng[19] = new Changcheng(258, 857); process(changcheng); } private static void process(Changcheng[] changcheng) { //按照end从小到大的顺序将所有区间进行排序 Arrays.sort(changcheng); int end = changcheng[0].getEnd(); int count = 1; System.out.println("第" + count + "个区间段为[" + changcheng[0].getBegin() + "," + end + "]"); for(int i=1; i<changcheng.length; i++) { //寻找不相交的区间 if(changcheng[i].getBegin() >= end) { count++; end = changcheng[i].getEnd(); System.out.println("第" + count + "个区间段为[" + changcheng[i].getBegin() + "," + end + "]"); } } System.out.println("最多有" + count + "个不重复的区间段"); } }
2、区间相关问题:区间选点问题
数轴上有n个闭区间[begin,end],取尽量少的点,使得每个区间内都至少有一个点(不同区间内含的点可以是同一个)
例如输入:
[0, 3] [16, 20] [2, 8] [8, 21] [15, 17] [10, 12] [19, 21]
输出
第1个点为:3 第2个点为:12 第3个点为:17 第4个点为:21 最少需要选择4个点
解题思路:使用贪心算法,贪心策略为按照end从小到大的顺序将区间排序(end相同时,begin从大到小排序),则如果出现区间包含的情况,小区间一定排在前面,每个区间取最后一个点。
public class Changcheng implements Comparable<Changcheng>{ private int begin; private int end; public Changcheng(int begin, int end) { this.begin = begin; this.end = end; } public int getBegin() { return begin; } public void setBegin(int begin) { this.begin = begin; } public int getEnd() { return end; } public void setEnd(int end) { this.end = end; } //按照end从小到大的顺序将区间排序(end相同时,begin从大到小排序) @Override public int compareTo(Changcheng o) { if(this.getEnd() > o.getEnd()) { return 1; }else if(this.getEnd() < o.getEnd()) { return -1; }else { if(this.getBegin() > o.getBegin()) { return -1; }else if(this.getBegin() < o.getBegin()) { return 1; } return 0; } } //判断当前区间是否包含指定点 public boolean contains(int point) { if(point >= this.getBegin() && point <= this.getEnd()) { return true; } return false; } }
import java.util.Arrays; public class Solution { public static void main(String[] args) { Changcheng[] changcheng = new Changcheng[7]; changcheng[0] = new Changcheng(0, 3); changcheng[1] = new Changcheng(16, 20); changcheng[2] = new Changcheng(2, 8); changcheng[3] = new Changcheng(8, 21); changcheng[4] = new Changcheng(15, 17); changcheng[5] = new Changcheng(10, 12); changcheng[6] = new Changcheng(19, 21); process(changcheng); } //区间选点问题 private static void process(Changcheng[] changcheng) { Arrays.sort(changcheng); int count = 1; int point = changcheng[0].getEnd(); System.out.println("第" + count + "个点为:" + point); for(int i=1; i<changcheng.length; i++) { if(!changcheng[i].contains(point)) { point = changcheng[i].getEnd(); count++; System.out.println("第" + count + "个点为:" + point); } } System.out.println("最少需要选择" + count + "个点"); } }