贪心算法——点灯问题

简介: 贪心算法——点灯问题

题目

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

package com.harrison.class09;
import java.util.HashSet;
public class Code03_Light {
  // 方法一:贪心
  public static int minLight1(String road) {
    char[] str = road.toCharArray();
    int index = 0;
    int lights = 0;
    while (index < str.length) {// 一旦越界,说明都已经决定好了,返回最少的灯数
      if (str[index] == 'X') {// i位置是X,直接去i++做决定
        index++;
      } else {// i位置是点 分情况讨论
        lights++;
        if (index + 1 == str.length) {// 不需要放灯了
          break;
        }
        if (str[index + 1] == 'X') {// i+1位置是X,必须在i位置放灯,然后去i+2位置做决定
          index = index + 2;
        } else {// i+1位置是. 不管i+2位置是X还是. 都在i+1位置放灯,然后去i+3位置做决定
          index = index + 3;
        }
      }
    }
    return lights;
  }
  // str[index....]位置,自由选择放灯还是不放灯
  // str[0..index-1]位置呢?已经做完决定了,那些放了灯的位置,存在lights里
  // 要求选出能照亮所有.的方案,并且在这些有效的方案中,返回最少需要几个灯
  public static int process2(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 {
      // str还没结束
      // i位置无论是'X'还是'.',都有一个选择,那就是不放灯
      // no 当前i位置没有放灯,返回后续的最好灯数
      int no = process2(str, index + 1, lights);
      int yes = Integer.MAX_VALUE;// yes 只有'.'才会变
      if (str[index] == '.') {
        lights.add(index);
        yes = process2(str, index + 1, lights);
        lights.remove(index);
      }
      return Math.min(no, yes);
    }
  }
  // 方法二:暴力解
  public static int minLight2(String road) {
    if (road == null || road.length() == 0) {
      return 0;
    }
    return process2(road.toCharArray(), 0, new HashSet<>());
  }
  public static String generateRandomString(int len) {
    char[] ans = new char[(int) (Math.random() * (len + 1))];
    for (int i = 0; i < ans.length; i++) {
      ans[i] = Math.random() < 0.5 ? 'X' : '.';
    }
    return String.valueOf(ans);
  }
  public static void main(String[] args) {
    int len = 20;
    int testTime = 100000;
    for (int i = 0; i < testTime; i++) {
      String test = generateRandomString(len);
      int ans1 = minLight1(test);
      int ans2 = minLight2(test);
      if (ans1 != ans2) {
        System.out.println("oops!");
      }
    }
    System.out.println("finish!");
  }
}
相关文章
|
27天前
【错题集-编程题】空调遥控(二分 / 滑动窗口)
【错题集-编程题】空调遥控(二分 / 滑动窗口)
|
1月前
|
算法
贪心算法个人见解
贪心算法个人见解
|
9月前
|
算法 Java 测试技术
LeetCode 周赛上分之旅 #46 经典二分答案与质因数分解
学习数据结构与算法的关键在于掌握问题背后的算法思维框架,你的思考越抽象,它能覆盖的问题域就越广,理解难度也更复杂。在这个专栏里,小彭与你分享每场 LeetCode 周赛的解题报告,一起体会上分之旅。
43 0
LeetCode 周赛上分之旅 #46 经典二分答案与质因数分解
|
11月前
微机原理:求解大数阶乘
微机原理:求解大数阶乘
|
算法 C++ Python
【每日算法Day 61】LeetCode 672. 灯泡开关 Ⅱ
【每日算法Day 61】LeetCode 672. 灯泡开关 Ⅱ
|
存储 算法
407. 接雨水 II : 经典 Dijkstra 运用题
407. 接雨水 II : 经典 Dijkstra 运用题
|
存储 算法
【趣学算法】贪心算法、海盗古董装船问题
贪心选择是指原问题的整体最优解可以通过一系列局部最优的选择得到,也就是先做出当前最优的选择,将原问题变为一个相似却规模更小的子问题,而后的每一步都是当前最优的选择。这种选择依赖于已做出的选择,但不依赖于未作出的选择。
102 0
|
机器学习/深度学习
带你轻松拿捏N皇后问题
要求任何两个皇后不同行、不同列,也不在同一 条斜线上
110 0
带你轻松拿捏N皇后问题
|
芯片
模电练习题-多路信号发生器(题目)
模电练习题-多路信号发生器(题目)
300 0
模电练习题-多路信号发生器(题目)
|
机器学习/深度学习 算法
<<算法很美>>——(六)——回溯算法(下)—N皇后问题
<<算法很美>>——(六)——回溯算法(下)—N皇后问题
<<算法很美>>——(六)——回溯算法(下)—N皇后问题