1.柠檬水找零(力扣860)
本题较为简单,只有三种情况,模拟每种情况即可,在接收20时用到了贪心,先尽量用10,再用5,因为10只能用于20的找零,而5既可以用于10的找零又可以用于20的找零。
public boolean lemonadeChange(int[] bills) { // if(bills[0] != 5) // return false; // //记录当前手头零钱数量 // HashMap<Integer,Integer> hashMap = new HashMap<>(); // int i = 0; // for (; i < bills.length; i++) { // if(bills[i] == 5) // hashMap.put(5, hashMap.getOrDefault(5,0)+1); // else break; // } // //给的都是5 // if (i == bills.length) // return true; // for (; i < bills.length; i++) { // if(bills[i] == 10 && hashMap.get(5)<1) // return false; // if(bills[i] == 5){ // hashMap.put(5,hashMap.get(5)+1); // } // if (bills[i] == 10 && hashMap.get(5)>=1){ // hashMap.put(10,hashMap.getOrDefault(10,0)+1); // hashMap.put(5,hashMap.get(5)-1); // continue; // } // if(bills[i] == 20){ // if(hashMap.containsKey(10) && hashMap.get(10)>=1 && hashMap.get(5)>=1){ // hashMap.put(20,hashMap.getOrDefault(20,0)+1); // hashMap.put(10,hashMap.get(10)-1); // hashMap.put(5,hashMap.get(5)-1); // continue; // } // else if(hashMap.get(5)>=3) // { // hashMap.put(20,hashMap.getOrDefault(20,0)+1); // hashMap.put(5,hashMap.get(5)-3); // continue; // } // else // return false; // } // } // return true; int five = 0; int ten = 0; for (int i = 0; i < bills.length; i++) { if(bills[i] == 5) five++; if(bills[i] == 10){ if (five>0){ five--; ten++; } else return false; } if(bills[i] == 20){ if(ten > 0 && five > 0){ ten--; five--; } else if(five>2) { five -= 3; } else return false; } } return true; }
2.根据身高重建队列(力扣406)
思路:首先由身高从小到大、前面人数从大到小排列,然后每次以前面人数k作为插入位置(前面有k个空位且当前位置还没有被占),也就是说身高低的先占位置,把前面给身高高的空下来,身高相同时位置靠后的先占,整体思路就是先后再前。
public int[][] reconstructQueue(int[][] people) { int[][] res = new int[people.length][2]; //每个位置初始化为[-1,-1],判断是否已经有人占位 for (int[] i:res ) { Arrays.fill(i,-1); } //按照身高从小到大排,身高相同时按前面人数从大到小排 Arrays.sort(people, new Comparator<int[]>() { @Override public int compare(int[] o1, int[] o2) { if(Integer.compare(o1[0],o2[0])==0) return -Integer.compare(o1[1],o2[1]); return Integer.compare(o1[0],o2[0]); } }); //排序后的数组按前面的空位数占住位置,先后再前。 for (int i = 0; i < people.length; i++) { int k = people[i][1]; int index = 0; while (k!=0){ if(res[index][0] == -1 && res[index][1] == -1){ k--; } index++; } while (res[index][0] != -1 && res[index][1] != -1) index++; res[index] = people[i]; } return res; }
3.用最小数量的箭引爆气球(力扣452)
贪心,每次要箭尽可能射的远,设立覆盖范围,超过范围时更新覆盖范围并增加一个弓箭。
public int findMinArrowShots(int[][] points) { if (points.length == 1) return 1; //按照气球结束坐标从小到大排,结束坐标相同时按照开始坐标从小到大排 Arrays.sort(points, new Comparator<int[]>() { @Override public int compare(int[] o1, int[] o2) { if(Integer.compare(o1[1], o2[1]) == 0) return Integer.compare(o1[0], o2[0]); return Integer.compare(o1[1], o2[1]); } }); //记录需要弓箭的数量 int res = 0; //记录当前弓箭能覆盖的最大范围 int range = Integer.MIN_VALUE; for (int i = 0; i < points.length; i++) { //当当前气球的开始坐标已经大于当前弓箭能到达的最大范围了,需要新的弓箭 if(points[i][0] > range) { //弓箭数加一 res++; //最大覆盖范围变为当前气球的结束坐标(贪心,每次弓箭尽可能射到最远) range = points[i][1]; } } return res; }
4.无重叠区间(力扣435)
与上题及其类似,先按照区间右端点排序,如果右端点相同,则按照区间左端点排序。遍历排序后的数组时若当前区间在范围的右端点前,则需要删除的区间数加一,否则更新覆盖范围的右端点。贪心:右区间靠前的尽可能先处理。
public int eraseOverlapIntervals(int[][] intervals) { if(intervals.length == 1) return 0; Arrays.sort(intervals, new Comparator<int[]>() { @Override public int compare(int[] o1, int[] o2) { if(Integer.compare(o1[1],o2[1]) == 0) return Integer.compare(o1[0],o2[0]); return Integer.compare(o1[1],o2[1]); } }); int res = 0; int range = intervals[0][1]; for (int i = 1; i < intervals.length; i++) { if(range>intervals[i][0]) { res++; } else range = intervals[i][1]; } return res; }
*5.划分字母区间(力扣763)
本题十分巧妙,值得复习!
public List<Integer> partitionLabels(String s) { /* 找到字符串中字符最后出现的位置,每次保存最远的那个,当遍历到最远的那个时, 得到的片段满足题意。 */ List<Integer> res = new ArrayList<>(); int curLong = 0; int begin = 0; for (int i = 0; i < s.length(); i++) { if(curLong < s.lastIndexOf(s.charAt(i))) curLong = s.lastIndexOf(s.charAt(i)); if(curLong == i){ res.add(i-begin+1); begin = i+1; } } return res; }
6.合并区间(力扣56)
本题较为容易,首先根据区间左端点排序,如果前面的区间包含了后面一个区间的左端点则继续遍历,否则全面的区间单独成为一个区间。
public int[][] merge(int[][] intervals) { if(intervals.length == 1) return intervals; List<int[]> list = new ArrayList<>(); Arrays.sort(intervals, new Comparator<int[]>() { @Override public int compare(int[] o1, int[] o2) { if(Integer.compare(o1[0], o2[0]) == 0) return Integer.compare(o1[1], o2[1]); return Integer.compare(o1[0], o2[0]); } }); int begin = intervals[0][0]; int end = intervals[0][1]; for (int i = 1; i < intervals.length; i++) { if(intervals[i][0] <= end) { //这里end应一直保持该区间内最大的右端点值 if(end < intervals[i][1]) end = intervals[i][1]; } else { list.add(new int[]{begin,end}); begin = intervals[i][0]; end = intervals[i][1]; } } list.add(new int[]{begin,end}); return list.toArray(new int[list.size()][]); }
7.单调递增的数字(力扣738)
本题需要知道,从后往前遍历这个数字时如果后面数的小于前一个数,则前一个数减一,后面的数开始都是9。注意去除前导0的情况。
public int monotoneIncreasingDigits(int n) { if(n == 0) return n; //记录从哪一位开始后面都变成9 int start = Integer.MAX_VALUE; char[] chars = String.valueOf(n).toCharArray(); for (int i = chars.length-1; i >0 ; i--) { if(chars[i] < chars[i-1]){ start = i; chars[i-1]--; } } StringBuilder res = new StringBuilder(); for (int i = 0; i < chars.length; i++) { //防止出现前导零 if(chars[i] =='0' && i == 0) continue; if(i < start) res.append(chars[i]); else res.append('9'); } return Integer.parseInt(res.toString()); }