牛客编程题--必刷101之贪心算法

前言

什么是贪心算法呢?

贪⼼算法可以认为是动态规划算法的⼀个特例,相⽐动态规划,使⽤贪⼼算法需要满⾜更多的条件(贪⼼选择性质),但是效率⽐动态规划要⾼。

效率分析

⼀个算法问题使⽤暴⼒解法需要指数级时间,如果能使⽤动态规划消除重叠⼦问题,就可以降到多项式级别的时间,如果满⾜贪⼼选择性质,那么可以进⼀步降低时间复杂度,达到线性级别的

基本原理(贪心选择性质)

每⼀步都做出⼀个局部最优的选择,最终的结果就是全局最优

找出整体当中给的每个局部子结构的最优解,并且最终将所有的这些局部最优解结合起来形成整体上的一个最优解。

举例说明

⽐如你⾯前放着 100 张⼈⺠币,你只能拿⼗张,怎么才能拿最多的⾯额?显然每次选择剩下钞票中⾯值最⼤的⼀张,最后你的选择⼀定是最优的。然⽽,⼤部分问题明显不具有贪⼼选择性质。⽐如打⽃地主,对⼿出对⼉三,按照贪⼼策略,你应该出尽可能⼩的牌刚好压制住对⽅,但现实情况我们甚⾄可能会出王炸。这种情况就不能⽤贪⼼算法,⽽得使⽤动态规划解决。

理论要结合实践,才能巩固知识,加深理解!

1、分糖果问题

题目描述:一群孩子做游戏,现在请你根据游戏得分来发糖果,要求如下:

  1. 每个孩子不管得分多少,起码分到一个糖果。
  2. 任意两个相邻的孩子之间,得分较多的孩子必须拿多一些糖果。(若相同则无此限制)
    给定一个数组 arrarr 代表得分数组,请返回最少需要多少糖果。

思路:要想分出最少的糖果,利用贪心思想,肯定是相邻位置没有增加的情况下,大家都分到1,相邻位置有增加的情况下,分到糖果数加1就好。什么情况下会增加糖果,相邻位置有得分差异,可能是递增可能是递减,如果是递增的话,糖果依次加1,如果是递减糖果依次减1?这不符合最小,因为减到最后一个递减的位置可能不是1,必须从1开始加才是最小,那我们可以从最后一个递减的位置往前反向加1.

具体步骤
step 1:使用一个辅助数组记录每个位置的孩子分到的糖果,全部初始化为1.
step 2:从左到右遍历数组,如果右边元素比相邻左边元素大,意味着在递增,糖果数就是前一个加1,否则保持1不变。
step 3:从右到左遍历数组,如果左边元素比相邻右边元素大, 意味着在原数组中是递减部分,如果左边在上一轮中分到的糖果数更小,则更新为左边的糖果数+1,否则保持不变。
step 4:将辅助数组中的元素累加求和

import java.util.*;


public class Solution {
    /**
     * pick candy
     * @param arr int整型一维数组 the array
     * @return int整型
     */
    public int candy (int[] arr) {
        // write code here
        int n = arr.length;
        if(n < 1)
            return n;
        int [] nums = new int[n];
        // 初始化所有值为1
        for(int i=0; i< n; i++){
            nums[i] = 1;
        }
        // 从左往右遍历
        for(int i=1; i< arr.length; i++){
            if(arr[i] > arr[i-1]) // 如果右边在递增,增加1
                nums[i] = nums[i-1]+1;
        }
        int res = nums[arr.length -1]; // 记录总数
        // 从右往左遍历
        for(int i= arr.length -2; i>=0; i--){
            if(arr[i] > arr[i+1] && nums[i] <= nums[i+1])
                nums[i] = nums[i+1] +1;
            res +=nums[i];
        }
        return res;
    }
}

2、主持人调度

题目描述:有 n 个活动即将举办,每个活动都有开始时间与活动的结束时间,第 i 个活动的开始时间是 start_{i} ,第 i 个活动的结束时间是 end_{i} ,举办某个活动就需要为该活动准备一个活动主持人。

要求:位活动主持人在同一时间只能参与一个活动。并且活动主持人需要全程参与活动,换句话说,一个主持人参与了第 i 个活动,那么该主持人在 (starti,endi) 这个时间段不能参与其他任何活动。求为了成功举办这 n 个活动,最少需要多少名主持人。

示例1
输入:2,[[1,2],[2,3]]
返回值:1
说明:只需要一个主持人就能成功举办这两个活动
示例2
输入:2,[[1,3],[2,4]]
返回值:2
说明:需要两个主持人才能成功举办这两个活动

具体思路: 排序+ 遍历比较
利用贪心思想,什么时候需要的主持人最少?那肯定是所有的区间没有重叠,每个区间首和上一个的区间尾都没有相交的情况,我们就可以让同一位主持人不辞辛劳,一直主持了。但是题目肯定不是这种理想的情况,那我们需要对交叉部分,判断需要增加多少位主持人。

具体步骤:
step 1: 利用辅助数组获取单独各个活动开始的时间和结束时间,然后分别开始时间和结束时间进行排序,方便后面判断是否相交。
step 2: 遍历nnn个活动,如果某个活动开始的时间大于之前活动结束的时候,当前主持人就够了,活动结束时间往后一个。
step 3: 若是出现之前活动结束时间晚于当前活动开始时间的,则需要增加主持人。

import java.util.*;
public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 计算成功举办活动需要多少名主持人
     * @param n int整型 有n个活动
     * @param startEnd int整型二维数组 startEnd[i][0]用于表示第i个活动的开始时间,startEnd[i][1]表示第i个活动的结束时间
     * @return int整型
     */
    public int minmumNumberOfHost (int n, int[][] startEnd) {
        // write code here
        int [] start = new int[n];
        int [] end = new int[n];
        
        for(int i = 0; i < n; i++){
            start[i] = startEnd[i][0];
            end[i] = startEnd[i][1];
        }
        Arrays.sort(start, 0 , start.length);
        Arrays.sort(end, 0, end.length);
        int res = 0;
        int j = 0;
        for(int i=0; i < n; i++){
            if(start[i] >= end[j])
                j++;
            else
                res++;
        }
        return res;
    }
}
  • 25
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 49
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

研行笔录

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值