贪心算法题目

455. 分发饼干

class Solution {
    /**
    思路:将尽可能多的饼干分出去->每人最好吃得刚刚饱->从饥饿度最低的和最小的饼干开始匹配
     */
    public int findContentChildren(int[] g, int[] s) {
        Arrays.sort(g);//将两个数组进行排序
        Arrays.sort(s);

        int i = 0;
        int j = 0;
        int count = 0;
        while(i < g.length && j < s.length){
            if(s[j] >= g[i]){//寻找最小的但能够符合最小饥饿值的饼干,若找到了,则将喂饱的人+1
                count++;
                i++;
            }
            j++;
        }

        return count;
    }
}

135. 分发糖果

class Solution {
    public int candy(int[] ratings) {
        /**
        1.初始化ans,使之全部为1
        2.从左到右看,如果ratings[right] > ratings[left],那么ans[right] = ans[left] + 1
        3.从右到左看,如果ratings[left] > ratings[right], and ans[left] <= ratings[right],then ans[left] = ans[right] + 1

        注意:顺序不能乱,不能是当左->右时,变化左边那个,因为这样就迭代不起来了
         */

         int[] ans = new int[ratings.length];
         for(int i = 0; i < ans.length; i++){//全部都分1颗糖果
             ans[i] = 1;
         }

         //从左往右,一个一个看
         for(int i = 0; i < ratings.length - 1; i++){//如果右边的分数比左边的高,那么右边的糖果要在左边的基础上+1(因为是要求至少,所以+1就可以了)
             if(ratings[i + 1] > ratings[i]){
                 ans[i + 1] = ans[i] + 1;
             }
         }

         //从右往左看
         for(int i = ratings.length - 1; i > 0; i--){//如果左边的分数比右边的高,但是左边得到的糖果不比右边的高,则左边得到的糖果变为右边糖果+1
             if(ratings[i - 1] > ratings[i] && ans[i - 1] <= ans[i]){
                 ans[i - 1] = ans[i] + 1;
             }

         }
         int sum = 0;
         for(int i = 0; i < ans.length; i++){//将记录下的糖果总总数加起来
             sum += ans[i];
         }
         return sum;

    }
}

435. 无重叠区间

class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
        /**
         找保留的最多区间数,也就是连接最紧密的所有区间
         1.先将所有的区间按右界排序
         2.取第一个区间的右界,看后面区间的左界是否在第一个区间内,如果在,则跳过这个区间,再判下一个区间,如果不在,那么最多区间数 + 1, 同时用于判断的右区间变为该区间的右区间,继续向下判断
         */

        Arrays.sort(intervals, new Comparator() {//将所有元素,按区间右界进行从小到大排序
            @Override
            public int compare(int[] o1, int[] o2) {
                if(o1[1] > o2[1]){
                    return 1;
                }
                
                if(o1[1] < o2[1]){
                    return -1;
                }else{
                    return 0;
                }
                
            }
        });

        int count = 1;
        int rightBound = intervals[0][1];//定义第一个右界
        for(int i = 0; i < intervals.length; i++){拿右界一个个比元素的左界
            if(intervals[i][0] >= rightBound){如果发现有元素的左界超出了前一个元素的右界,那么说明这个区间并没有重合,则把新的右界赋值
                count++;
                rightBound = intervals[i][1];
            }
        }
        
        return intervals.length - count;
    }
}

122. 买卖股票的最佳时机 II

class Solution {
    public int maxProfit(int[] prices) {
        /**
        从头到尾遍历,如果发现prices[i + 1] - prices[i] > 0, then sum+=, i++
         */

        if(prices.length == 1){
            return 0;
        }
        int sum = 0;
         for(int i = 0; i < prices.length - 1; i++){
             if(prices[i + 1] - prices[i] > 0){
                 sum += prices[i + 1] - prices[i];
             }
         }
         return sum;

    }
}

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

class Solution {
    public int findMinArrowShots(int[][] points) {
        /**
        1.将points按照元素的右界进行排序,去一个元素的右界,判断剩下元素的左界是否在取出的右界之内,如果是,则判断下一个,如果不是,则跳到下一个元素的右界,同时count++;
         */
         int count = 1;
        Arrays.sort(points, new Comparator() {
            @Override
            public int compare(int[] o1, int[] o2) {
                if(o1[1] > o2[1]){
                    return 1;
                }

                if(o1[1] < o2[1]){
                    return -1;
                }else{
                    return 0;
                }

            }
        });

        int rightBound = points[0][1];
        for(int i = 0;i < points.length; i++){
            if(points[i][0] > rightBound){如果有气球没有重合,那么需要多一把箭,count++,然后按新气球所在的范围再判定后面的气球
                rightBound = points[i][1];
                count++;
            }
        }

        return count;
    }
}

376. 摆动序列

class Solution {
    public int wiggleMaxLength(int[] nums) {
        /*
        思路:贪心算法,从左到右,把所有符合条件的,先全部记录下来再说
         */


        /**
        设置一个count,用来记录属于摆动序列的元素个数,从头到尾开始找。设置一个flag,用来判断下一个元素的差值需要的是正的还是负的,如果当前元素的差值为负数,那么flag=1, 正数则为-1,如果两个是相同的元素,那么flag = 0;
         */
        if(nums.length == 1){
            return 1;
        }

        if(nums.length == 2 && nums[0] == nums[1]){
            return 1;
        }
         int count = 1;
         if(nums[0] != nums[1]){
             count = 2;
         }

         int flag = -1 * (nums[1] - nums[0]);
        int res = 0;
        for(int i = 2; i < nums.length; i++){
            res = nums[i] - nums[i - 1];
            //res < 0 and flag <= 0
            //res > 0 and flag >= 0
            if(res < 0 && flag <= 0){
                count++;
                flag = -1 * res;
            }

            if(res > 0 && flag >= 0){
                count++;
                flag = -1 * (res); 
            }

        }
        return count;

    }
}
class Solution {
    public int wiggleMaxLength(int[] nums) {
        if(nums.length == 1){
            return 1;
        }

        int preDiff = 0;//前一个差值,如果前一个是谷底,则是>=0,前一个是顶峰,则是<=0
        int curDiff = 0;//当前一对差值
        int count = 1;//因为最右边必定会有一个峰值
        for(int i = 0; i < nums.length - 1; i++){
            curDiff = nums[i + 1] - nums[i];

            if((curDiff > 0 && preDiff <= 0) || (curDiff < 0 && preDiff >= 0)){//若pre是谷底,还没有走到顶峰,或若pre是顶峰,还没有走到谷底的时候,i就一直++,直到符合if这个条件
                count++;
                preDiff = curDiff;
            }
        }

        return count;
    }
}



53. 最大子序和

class Solution {
    public int maxSubArray(int[] nums) {
        /**
        从头开始加,如果加到发现tempSum是<0的,那么就将tempSum清零,从下一个元素重新加起,将最大的那个记录在maxSum里面
         */
         int maxSubArray = nums[0];
         int tempSum = 0;

         for(int i = 0; i < nums.length; i++){
             tempSum += nums[i];
             maxSubArray = Math.max(tempSum, maxSubArray);//必须在这里就开始调换,因为nums有可能全部都是负数,如果全是负数,
//则也是要在负数中找最大,而不是让后面被赋予0之后再找,因为0只是一个置零的效果,不是nums里面的元素

             if(tempSum < 0){
                 tempSum = 0;
             }
         }

         return maxSubArray;
    }
}

55. 跳跃游戏

class Solution {
    public boolean canJump(int[] nums) {
        if(nums.length == 1){
            return  true;
        }
        /**
         设定一个cover,第一个cover取第一个元素,此时cover的范围是[0, cover],在这个范围内找数组中的元素,看是否有i + nums[i] > cover的,
如果有,则跳到该元素这里,修改cover为i + nums[i],重复上面的判断。
每一次cover进行改变之后都要看看是否已经能覆盖到最后一个元素了,如果能,在返回true,如果经过了cover都不能,则返回false
         */

        int cover = nums[0];
        for(int i = 0; i <= cover; i++){//[i, cover]
            cover = Math.max(i + nums[i], cover);
            
            if(cover >= nums.length - 1){
                return true;
            }
        }
        return false;
    }
}

45. 跳跃游戏 II

class Solution {
    public int jump(int[] nums) {

    /**
    思路:到了一个元素之后,找这个元素cover的范围中,能够cover最多范围的元素,然后进行一次跳跃,得到新的范围,直到能够cover到最后的点
     */

        /**
         要选取最少,那么就是每次都要跳得最远

         设定一个cover,cover的最开始的值就是第一个元素所能包含的范围,在这个范围内,寻找能够跳的最远的元素,然后cover改成能跳得最远元素的值
         */
        if(nums.length == 1){
            return 0;
        }

        int i = 0;
        int count = 1;
        int cover = i + nums[i];
        while(true){
            if(cover >= nums.length - 1){
                return count;
            }else{
                int maxDistance = cover;
                int targetIndex = i;
                for(int j = i + 1; j <= i + nums[i]; j++){
                    if(j + nums[j] > maxDistance){
                        maxDistance = j + nums[j];
                        targetIndex = j;
                    }
                }
                cover = maxDistance;
                i = targetIndex;
                count++;
            }
        } 
    }
}
    public int jump(int[] nums) {
        if(nums.length == 1){
            return 0;
        }

        int curDistance = 0;//当前cover的范围
        int nextDistance = 0;//在cover范围中,某一元素能够cover的最大范围
        int count = 0;
        int i = 0;
        while(true){
            nextDistance = Math.max(nextDistance, i + nums[i]);//取cover中某一元素能够cover的最大范围

            if(nextDistance >= nums.length - 1){//如果知道了该元素能够cover的范围已经到结尾了
                count++;
                return count;
            }

            if(i == curDistance){//如果已经到了当前cover的最后,那么就要进行跳跃,并且将当前的cover,换为在遍历cover范围的过程中找到的新的最大的cover的范围
                curDistance = nextDistance;
                count++;
            }
            i++;
        }
    }

763. 划分字母区间

class Solution {
    public List partitionLabels(String s) {
        /**
        思路:
        计算s中每一个字符出现的最后的位置,放置在edge中,然后从头开始查询字符,设定一个right值,
right值就是某一个字符出现的最后一个位置,在[i, right]的查询过程中,如果出现了更加大的right,那么
更新right,直到i == right,表明已经到了刚刚遍历过这串字串的最后一个字符
         */

        List list = new LinkedList<>();
        int[] edge = new int[26];
        char[] chars = s.toCharArray();

        for(int i = 0; i < chars.length; i++){
            edge[chars[i] - 'a'] = i;//如果是同一个字符,那么chars[i] - 'a'就是相同的,那么该索引的值就能被更新
        }

        int right = 0;
        int previous = -1;//设定-1是因为,对于第一串字符串,长度是right - 0 + 1
        for(int i = 0; i < chars.length; i++){
            right = Math.max(right, edge[chars[i] - 'a']);//按字母排的,而不是按索引排的

            if(i == right){
                list.add(i - previous);
                previous = i;
            }
        }

        return list;

    }
}

56. 合并区间

class Solution {
    public int[][] merge(int[][] intervals) {
        /**
         思路:因为合并之后的元素个数可能会发生改变,所以采用ArrayList
         将区间按左边界进行排列,记录下每一次新元素的左边界start, 然后进行遍历,
         如果intervals[i][左边界] < intervals[i - 1][右边界],那么对intervals[i]进行扩大,
         扩大为intervals[i]和intervals[i - 1]中,有边界更大的那个,
         即intervals[i][1] = Math.max(intervals[i][1], intervals[i - 1][1])
         
         
         */

        List res = new ArrayList<>();
        Arrays.sort(intervals, new Comparator() {//按左边界进行排序,按有边界会出错
            @Override
            public int compare(int[] o1, int[] o2) {
                if(o1[0] > o2[0]){
                    return 1;
                }

                if(o1[0] < o2[0]){
                    return -1;
                }else{
                    return 0;
                }
            }
        });

        int start = intervals[0][0];
        for(int i = 1; i < intervals.length; i++){
            if(intervals[i][0] > intervals[i - 1][1]){
                res.add(new int[]{start, intervals[i -  1][1]});
                start = intervals[i][0];
            }else{
                intervals[i][1] = Math.max(intervals[i - 1][1], intervals[i][1]);//若发生重合了,则进行修改,将该区间不断地扩大,
                //使之产生一种递进的方式
            }
        }
        res.add(new int[]{start, intervals[intervals.length - 1][1]});//将最后一个元素所覆盖的范围放进去
        return res.toArray(new int[res.size()][]);
    }
}

待后续补充

你可能感兴趣的:(算法,java)