代码随想录-贪心算法【2】(Java)

柠檬水找零

链接: 860.柠檬水找零

思路

本题思路非常简单

主要是抓住问题的本质,没有抓住问题的本质,很容易被一些无关紧要的细节困住。

认真审题,情况也不多,把各种情况列一下呗。

代码

自己的代码,if结构太多,冗长,容易出错

class Solution {
    public boolean lemonadeChange(int[] bills) {
        int five = 0;
        int ten = 0;
        int twenty = 0;
        for (int i = 0;i < bills.length;i++){
            if (bills[i] == 5)
                five++;
            else if (bills[i] == 10){
                if (five > 0){
                    five--;
                    ten++;
                }else{
                    return false;
                }
            }
            else if (bills[i] == 20){
                if (ten > 0 && five > 0){
                    ten--;
                    five--;
                }else if(ten == 0 && five > 2){
                    five = five - 3;
                }
                else return false;
            }
        }
        return true;
    }
}

官方代码

class Solution {
    public boolean lemonadeChange(int[] bills) {
        int five = 0;
        int ten = 0;

        for (int i = 0; i < bills.length; i++) {
            if (bills[i] == 5) {
                five++;
            } else if (bills[i] == 10) {
                five--;
                ten++;
            } else if (bills[i] == 20) {
                if (ten > 0) {
                    ten--;
                    five--;
                } else {
                    five -= 3;
                }
            }
            if (five < 0 || ten < 0) return false;
        }
        
        return true;
    }
}

在前面的判断中,只考虑有的情况,没有的情况正常操作;最后再判断按正常操作下的ten和five是否为负数,有负数说明我们在不符合条件的情况下操作了,所以报错。

根据身高重建队列

链接: 406.根据身高重建队列

思路

本题的思路很简单,主要是二维数组看起来会比较复杂

但熟悉java语言的语法,本题会比较简单

思路就是按身高从大到小排列,身高相同的按k值,小的在前

然后再调整顺序

在java语言中,身高排序是用排序算法(自己会经常遗忘)

调整顺序用的是按k值插入

代码

class Solution {
    public int[][] reconstructQueue(int[][] people) {
        Arrays.sort(people,(a,b) -> {
            if (a[0] == b[0])   return a[1] - b[1];
            return b[0] - a[0];
        });
        LinkedList<int[]> que = new LinkedList<>();
        for (int[] p : people){
            que.add(p[1],p);
        }
        return que.toArray(new int[people.length][]);
    }
}

每一步自己都不太熟悉,要记住本题。

PS:定义队列时ArrayList也可以

用最少数量的箭引爆气球

链接: 452. 用最少数量的箭引爆气球

思路

思路很简单,但自己容易想太多

先按左区间排序,排完序后只要前一元素的左区间小于后一元素的右区间,则不重合,计数。

若重合,则进行之后的比较,在比较之前,我们应决定重合后区间他们的最小右区间。

然后这个右区间是新的比较中的左区间

代码

class Solution {
    public int findMinArrowShots(int[][] points) {
        // Arrays.sort(points,(a,b) -> {
        //     return a[0] -b[0];
        // });
        // 报错
        // 最后执行的输入:[[-2147483646,-2147483645],[2147483646,2147483647]]
        Arrays.sort(points, (a, b) -> Integer.compare(a[0], b[0]));
        int result = 1;
        for (int i = 1;i < points.length;i++){
            if (points[i - 1][1] < points[i][0]){
                result++;
            }else{
                points[i][1] = Math.min(points[i - 1][1],points[i][1]);
            }
        }
        return result;
    }
}

注意看范围吧,如果数字的范围属于正负都有,且很大的情况,最好使用Integer

无重叠区间

链接: 435. 无重叠区间

思路

本题其实和452.用最少数量的箭引爆气球 (opens new window)非常像,弓箭的数量就相当于是非交叉区间的数量,只要把弓箭那道题目代码里射爆气球的判断条件加个等号([0,1]和[1,2]不是重叠区间),然后用总区间数减去弓箭数量 就是要移除的区间数量了。

代码

class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
        Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0]));
        int result = 1;
        for (int i = 1;i < intervals.length;i++){
            if (intervals[i - 1][1] <= intervals[i][0]){
                result++;
            }else{
                intervals[i][1] = Math.min(intervals[i - 1][1],intervals[i][1]);
            }
        }
        return intervals.length - result;
    }
}

对于二维数组而言,

intervals.length求的是行数

intervals[0].length求的是列数

划分字母区间

链接: 763.划分字母区间

思路

自己属于代码能力略差

有思路但不知道能不能用代码实现,所以不确定自己的思路是否可行,也可能因为不熟悉代码,所以不敢有思路;

涉及到相同不同字符串的,可以考虑一下使用哈希表

第一次遍历,记录一下字母的最远位置

设置left和right区间左边界和右边界

第二次遍历,利用哈希表来求右边界的最大值,当i遍历到右边界时,说明这个区间已经找到,将该区间的长度加入到result中,left = right + 1,接着遍历。

很顺畅的思路,我手写我心,因为自己代码能力较差,所以没有想到这种思路。

代码

class Solution {
    public List<Integer> partitionLabels(String s) {
        int[] hash = new int[27];
        for (int i = 0;i < s.length();i++){
            hash[s.charAt(i) - 'a'] = i;
        }
        // 注意审题
        List<Integer> result = new ArrayList<>();
        int left = 0;
        int right = 0;
        for (int i = 0;i < s.length();i++){
            right = Math.max(right,hash[s.charAt(i) - 'a']);
            if (i == right){
                result.add(right - left + 1);
                left = right + 1;
            }
        }
        return result;
    }
}

合并区间

链接: 56. 合并区间

思路

本题思路很简单,但自己思考不全面(在草稿纸上列一下诶,不要纯用脑子想)报错了很多次

主要有两个重要思想:合并,以及回溯

合并分三种情况,最普通的合并,以及两种包含(报错了至少三次)

intervals[i][0] = Math.min(intervals[i - 1][0],intervals[i][0]);
intervals[i][1] = Math.max(intervals[i - 1][1],intervals[i][1]);

不管是哪种情况,左边界取两个元素中最小的左边界,右边界取两个元素中最大的右边界

还有回溯:前一个元素进行完操作,加入结果中,但如果下一个元素需要与前一个元素进行合并操作再加入,这样结果就重复了,所以我们需要回溯,加入之后如果需要该元素进行处理,我们将该元素删除。

代码

class Solution {
    public int[][] merge(int[][] intervals) {
        if (intervals.length == 1) return intervals;
        Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0]));
        // 首先要找到重叠的区间
        ArrayList<int[]> result = new ArrayList<>();
        int num = intervals.length;
        result.add(intervals[0]);
        for (int i = 1;i < intervals.length;i++){
            // 重叠
            if (intervals[i - 1][1] >= intervals[i][0]){
                intervals[i][0] = Math.min(intervals[i - 1][0],intervals[i][0]);
                intervals[i][1] = Math.max(intervals[i - 1][1],intervals[i][1]);
                num--;
                result.remove(result.size() - 1);
            }
            result.add(intervals[i]);
        }
        return result.toArray(new int[num][]);
    }
}

单调递增的数字

链接: 738.单调递增的数字

思路

思路很简单,主要是自己思维不全面 (容易漏情况)加之不知道如何用代码去实现

强迫自己有条理地思考

针对不是递减的数字,从后往前遍历,如果不符合条件,前面的元素–,记录下当前元素的下标,继续遍历;然后在记录的下标开始往后的数都赋值为9

我自己能察觉到一点,不太自信。

代码

class Solution {
    public int monotoneIncreasingDigits(int n) {
        String str = String.valueOf(n);
        char[] chars = str.toCharArray();
        int flag = chars.length;
        for (int i = chars.length - 1;i > 0;i--){
            if (chars[i -1] > chars[i]){
                chars[i - 1]--;
                flag = i;
            }
        }
        for (int i = flag;i < chars.length;i++){
            chars[i] = '9';
        }
        return Integer.parseInt(String.valueOf(chars));
    }
}

JAVA 中int类型转String类型的三种通常方法:

1、String.valueOf(int i)

2、Integer.toString(int i)

3、i + “”; //i 为 int类型,int+string型就是先将int型的i转为string然后跟上后面的空string。

三种方法效率排序为:

Integer.toString(int i) > String.valueOf(int i) > i+“”

最后的return 挺有意思的

监控二叉树

链接: 968.监控二叉树

思路

看起来很复杂,也是困难难度

本质还是二叉树的遍历

节点的三种状态:

0:无覆盖

1:有覆盖

2:有摄像头

终止条件:

空节点默认为有覆盖的状态,避免在叶子节点上放摄像头

单层逻辑:

如果左右节点都为1(有覆盖),则返回0

左右节点若有一个0(无覆盖),则返回2

左右节点若有一个2(有节点),则返回1

在主函数中如果返回的root节点为0,无覆盖的情况,我们仍要将result++

在if语句中,如果if语句外没有return返回值,则if语句需要将所有的情况都包含

代码

class Solution {
    int result = 0;
    int traversal(TreeNode root){
        if (root == null)   return 1;
        int left = traversal(root.left);
        int right = traversal(root.right);
        if (left == 1 && right == 1){
            return 0;
        }else if (left == 0 || right == 0){
            result++;
            return 2;
        }else{
             return 1;
        } 
    }
    public int minCameraCover(TreeNode root) {
        if (traversal(root) == 0)
            result++;
        return result;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值