02、贪心算法-放灯问题

题目:

给定一个字符串str,只由‘X’和‘.’两种字符构成。
‘X’表示墙,不能放灯,也不需要点亮
‘.’表示居民点,可以放灯,需要点亮
如果灯放在i位置,可以让i-1,i和i+1三个位置被点亮
返回如果点亮str中所有需要点亮的位置,至少需要几盏

 图示:

1、暴力解决方案

1.1、思路:

观察题目要求,我的思路是,每个点都可以选择放灯或不放灯(X一定不能放灯)。

那么我们可以从开头位置开始遍历

index位置选择放灯,然后去index+1位置找可能性。

idnex位置选择不放灯,然后去index+1位置找可能性。

直至遍历完毕,然后判断该可能性是否可以照亮所有。

最后从所有可能性中选择最优的方案。

1.2、代码: 

//方案1:暴力方案
public static int minLight1(String road) {
    if (road == null || road.length() == 0) {
        return 0;
    }
    return process(road.toCharArray(), 0, new HashSet<>());
}

//str[index......] 位置,自由选择放灯还是不放等
//str[0,index-1]位置呢?已经做完决定了,那么放了灯的位置存放在lights集合中
//求出所有都能照亮的方案,并且在这些有效的方案中,返回最少需要多少盏灯
public static int process(char[] str, int index, HashSet<Integer> lights) {
    if (index == str.length) {//说明已经遍历结束了
        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();
    } else {
        //当前不管是X还是点,都可以选择不放灯(X一定不能放)。
        //也就是当前index位置不放灯,你去index+1位置给我返回最好的放灯数目
        int no = process(str, index + 1, lights);

        int yes = Integer.MAX_VALUE;
        //如果index位置是点,那么我可以做出一个放灯的决定
        if (str[index] == '.') {
            //把需要放灯的位置加入到lights集合中,用完之后记得要移除掉
            lights.add(index);
            yes = process(str, index + 1, lights);
            lights.remove(index);
        }
        //从当前位置不放灯和放灯得到的值之中取最小值
        return Math.min(no, yes);
    }
}

 2、贪心解决方案

1.1、思路:

观察题目要求,我们可以考虑,如何不用关心前面的结果,只与后面的有关呢?如果当前是一个X,那么继续看下一个。如果当前是点,则我们看下一个位置是什么?如果也是点,则灯的位置应该就是在第二个位置,这就是我们的贪心策略,选择靠后的位置放灯,此时,当我们把第二个位置放灯后,我们根本就不用考虑第三个位置了,因为第三个位置无论是什么,都已经涵盖在灯的范围内了,此时直接跳到第四个位置重新判断。 同时,当第二个位置不是点时,说明只能在第一个位置放灯,此时,直接跳到第三个位置判断。

 

1.2、代码:

//方案2:贪心算法(我总是在当前步做出最右的决定)
public static int minLight2(String road) {
    char[] str = road.toCharArray();
    int index = 0;
    int light = 0;
    while (index < str.length) {
        if (str[index] == 'X') {//如果当前位置是X,直接跳转到下一个位置去
            index++;
        } else {
            //如果位置是点,那么一定需要添加一盏灯了
            light++;
            if (index + 1 == str.length) {//如果当前位置的下一个正好到末尾了,那么直接退出
                break;
            } else {
                if (str[index + 1] == 'X') {
                    //如果当前位置是X,比如(.X),那么你就去index+2位置去做决定
                    index = index + 2;
                } else {
                    //如果当前位置是点,比如(..),那么你就去index+3位置去决定
                    index = index + 3;
                }
            }
        }
    }
    return light;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值