最少时间收集RGB灯(滑动窗口)

128 阅读2分钟

问题描述

小R在参观一个拥有 N 个商店的市场,每个商店包含一种类型的灯——红灯 R、绿灯 G 或蓝灯 B。市场中的商店由字符串 S 表示,其中每个字符对应商店的灯类型,商店的编号从 0 到 N-1

小R可以从任意商店开始旅程,并在每分钟内从当前商店移动到下一个商店(i 到 i+1)。他需要收集每种类型的灯 RG 和 B 各至少一个,并且他想在尽可能少的分钟内完成任务。

你的任务是帮助小R计算收集所有三种灯(RGB)所需的最少分钟数。如果无法收集到所有三种灯,返回 -1

例如:当 N = 5 且 S = "RRGGB" 时,最少需要的时间是 3 分钟,因为从第一个商店(S[0])开始,移动 3 分钟后可以收集到所有三种灯。


测试样例

样例1:

输入:N = 5,S = "RRGGB"
输出:3

样例2:

输入:N = 4,S = "RRRR"
输出:-1

样例3:

输入:N = 6,S = "RGBRGB"
输出:2

我们可以使用滑动窗口,在RGB三种灯都有的情况下循环移动和改变窗口大小,更新并记录窗口的最小值:

public class Main {
    public static int solution(int N, String S) {
        int[] rgb=new int[3];//三个元素分别代表RGB
        int i,start,end,min;
        for(i=0;i<N;i++){
            add(rgb,S.charAt(i));
        }
        if(!check(rgb)){
            return -1;
        }
        for(i=0;i<3;i++){
            rgb[i]=0;
        }
        start=end=0;
        //[start,end)里面的元素
        min=Integer.MAX_VALUE;
        while(end<N){
            while(!check(rgb)&&end<N){
                add(rgb,S.charAt(end++));
            }
            while(check(rgb)){
                sub(rgb,S.charAt(start++));
            }
            min=Math.min(min,end-start);
        }
        return min;
    }
    //检查三种灯是否收集完
    public static   boolean check(int[] rgb){
        return rgb[0]*rgb[1]*rgb[2]>0;
    }
    public static void add(int[] rgb, char ch){
        switch (ch){
            case 'R':{
                rgb[0]++;
                break;
            }
            case 'G':{
                rgb[1]++;
                break;
            }
            case 'B':{
                rgb[2]++;
            }
        }
    }
    public static void sub(int[] rgb,char ch){
        switch (ch){
            case 'R':{
                rgb[0]--;
                break;
            }
            case 'G':{
                rgb[1]--;
                break;
            }
            case 'B':{
                rgb[2]--;
            }
        }
    }


    public static void main(String[] args) {
        System.out.println(solution(5, "RRGGB") == 3);
        System.out.println(solution(4, "RRRR") == -1);
        System.out.println(solution(6, "RGBRGB") == 2);
    }
}
  1. 算法步骤

    • 首先遍历字符串S,统计每种灯的数量,并检查是否包含所有三种灯。如果不包含,直接返回-1。
    • 初始化rgb数组,将startend指针置于字符串的开始位置。
    • 使用滑动窗口的思想,不断扩大end指针,直到包含所有三种灯。然后尝试缩小start指针,寻找最小的窗口大小。
    • 更新最小分钟数min
    • 循环直到end指针到达字符串末尾。