贪心策略:求一条街上最少应该放多少盏灯,才能照亮整条街的商户

本文介绍了如何使用贪心策略解决一个街道照明问题,即如何放置最少数量的灯来照亮所有商户。文章通过一个示例解释了贪心算法的思路,并提供了相应的Java代码实现。同时,文章强调了贪心策略在互联网大厂笔试中的重要性,但指出在面试中更侧重于算法优化。最后,文章提供了一个暴力解法作为贪心策略的验证,并得出贪心策略的正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

贪心策略:求一条街上最少应该放多少盏灯,才能照亮整条街的商户?

提示:从本文开始,咱们来说贪心策略系列文章!!

贪心策略在互联网大厂的招聘笔试和面试中的地位!!!在笔试中考贪心,而面试不考贪心。

(1)贪心在笔试中:75%的考题都是贪心策略,为啥呢,一方面考你的聪明程度,另一方面,考你的代码编写能力;所以我参加过的笔试证明了这一点,往往大厂给你三个算法题,第1道题一定是贪心,排序结合的算法题,你需要懂点脑子,了解一下排序和堆啥的数据结构,还得会点贪心技巧,才能设计出来;
(2)面试不怎么考贪心策略,为什么?因为面试考你的是算法的优化能力,所以如果给你贪心的话,你一下子想到了解决方案,也不谈什么优化的事情,没意义,所以不考贪心。
(3)你必须要认识到:最简单的是国内的面试过程(嘴说的事情,都好办),难度中上等的是国外的笔试面试,最难的国内的算法笔试。 那么,你一定要明白,最难的还是国内的算法笔试题!!!因此要多练,多学,多见题,多思考,多总结,才能拿下。

以下是贪心策略基础题目系列文章:
(1)贪心策略:请你计算i×arr[i]的累加和最大值
(2)贪心策略:请你设计最优的安排会议日程表,以使得举行的会议数最多


题目

一条街道,由.和x组成,.代表商户,x代表墙体
.需要灯来照亮,x可以隔绝灯光,也不需要照亮
一盏灯,可以照亮3家连续的商户…,只需要放在中间位置那家商户就行。
给你一条街,road,请你求这一条街上应该放多少盏灯,才能照亮整条街?


一、审题

示例:
比如:一家人,至少要一盏灯,2家也至少需要一盏灯,3家,连续的话,可以考虑放中间一盏灯
在这里插入图片描述


二、贪心策略解题:当前位置i做最好的决策

其实这么看:
咱们从左往右,i=0–N-1位置决定,放灯吗?放N++,不放不管

(1)如果你i位置是x,那不好意思,N不动,让我们去看i+1位置吧
在这里插入图片描述

(2)如果你i位置是.,至少,咱必须先放一盏灯,咱先不看后面的情况
——如果此时i+1是x,那自然刚刚放灯没问题,让咱们去i+2位置决定吧
在这里插入图片描述
——如果此时i+1是.,那自然刚刚放灯没问题,这个时候,我们再考虑一下i+2的情况
其实,i+2那里,不论是x还是.都没关系,刚刚放那个灯是必须的,为啥呢?
在这里插入图片描述
你是…x起码要一盏灯,灯放在i或者i+1都行,我不管,我只看要几盏灯?
你是…也起码要一盏灯,只需要在中间位置i+1那放灯就行,能照亮3家商户:
在这里插入图片描述
故在i为.且i+1也是.的情况下,咱就要放一盏灯,不看i+2,直接去看i+3位置就行。

(3)中途遇到i+1已经是越界了的话,过程结束。返回N;

因此这个就是本题的贪心策略:在当前i位置,做最好的选择,依据i+1和i+2位置的情况,做最佳选择!!
手撕代码

//复习:放灯放几个?在当前i位置,做最佳决策
    public static int NofLights(String road){
        if (road == null || road.compareTo("") == 0) return 0;

        char[] str = road.toCharArray();
        int i = 0;//索引str
        int N = str.length;//str长
        int k = 0;//放多少盏灯呢?

        while (i < N){
            //越界就不行
            //(1)如果你i位置是x,那不好意思,N不动,让我们去看i+1位置吧
            if (str[i] == 'x') i++;
            //(2)如果你i位置是.,至少,咱必须先放一盏灯,咱先不看后面的情况
            else {
                //不管后面啥情况,都得增加一盏灯
                k++;
                //又看i+1处是啥呢?
                if (i + 1 == N) break;//如果i+1不存在,结束
                if (str[i + 1] == 'x') i += 2;//直接去看i+2,因为必定放一个灯
                else {//str[i + 1] == '.',要写成if else哦,否则就出错了
                    i += 3;//不管i+2是.还是x,都需要在i+1处放一个灯,照亮3家,直接去看i+3
                }
            }
        }

        //全部对比完,返回k
        return k;
    }

暴力解验证贪心策略是否正确?

暴力解,除了x的地方,咱们再每一个位置,都放,或者不放,2个方案
做一个排列组合

把所有位置放的情况都有了以后
咱再核查.的地方,看看是不是多放了,多放了移除,保证.x,…x,…这仨情况都只需要放一盏灯就行。
然后就看剩下多少盏灯,这绝对就是正确的结果。

——显然,搞排列组合,绝对是浪费时间,还要额外空间,麻烦得很。

//暴力解法,挨个放还是不放
    //给str字符串放灯,从i位置开始放,i前的放好了,放好的灯的位置搁进lights中,
    //放回最少需要放几盏灯的数量
    public static int process(char[] str, int index, HashSet<Integer> lights){
        if (index != str.length){
            //如果index,还没有到str长度,说明位置还没有放完,需要考虑
            //在index,放还是不放,别忘了清理现场,保证放和不放的可能性
            int yes = Integer.MAX_VALUE;
            if (str[index] == '.'){//得是点才能放
                lights.add(index);//-----放了就意味着这里lights加index,之后还要考虑现场
                yes = process(str, index + 1, lights);
                lights.remove(index);//清理现场
                //----排列组合的关键
            }

            int no = process(str, index + 1, lights);//不放就light不操作

            return Math.min(yes, no);//返回放和不放的方案的最小值
        }else {
            //说明index==str.length
            //既然方案已经成了,就要看它合格与否,不合格还是返回无穷大
            //合格就返回它的size
            for (int i = 0; i < str.length; i++) {
                if (str[i] != 'x'){
                    //只看.
                    if (!lights.contains(i - 1) &&
                    !lights.contains(i) &&
                    !lights.contains(i + 1)) return Integer.MAX_VALUE;
                }
            }
            //全部审核结束,没问题
            return lights.size();
        }
    }

    //调用暴力函数
    public static int leastLights(String road){
        if (road == null || road.length() == 0) return 0;
        HashSet<Integer> lights = new HashSet<>();
        return process(road.toCharArray(), 0, lights);
    }

然后咱们验证一下贪心是否正确???

public static void checker(){
        String road = "x.x......xx.xx..x...x.x..x";
        int min = leastLights(road);
        int min2 = leastLights2(road);
        int min3 = NofLights(road);

        System.out.println(min == min2 ? "right!" : "oops!wrong!");
        System.out.println(min == min3 ? "right!" : "oops!wrong!");
    }

    public static void main(String[] args) {
        checker();
    }

结果是OK的

right!
right!

总结

提示:重要经验:

1)贪心策略的唯一解决办法就是多见,多练,多总结,培养敏感度!
2)本题的贪心就在定义,只要i+1的位置确定了,咱就能决定当前i位置放几盏灯,知晓下一次直接去i+2呢还是i+3位置决定。
3)笔试求AC,可以不考虑空间复杂度,但是面试既要考虑时间复杂度最优,也要考虑空间复杂度最优。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

冰露可乐

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

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

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

打赏作者

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

抵扣说明:

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

余额充值