打开代码随想录Day14

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());
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值