灯都亮起来问题

1,017 阅读2分钟

「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战」。

给定一个数组arr,长度为N,arr中的值不是0就是1。arr[i]表示第i栈灯的状态,0代表灭灯,1代表亮灯 每一栈灯都有开关,但是按下i号灯的开关,会同时改变i-1、i、i+1栈灯的状态

问题一:如果N栈灯排成一条直线,请问最少按下多少次开关?

问题二:如果N栈灯排成一个圈,请问最少按下多少次开关,能让灯都亮起来

一、分析

N栈灯排成一条直线:

  1. i为中间位置时,i号灯的开关能影响i-1、i和i+1
  2. 0号灯的开关只能影响0和1位置的灯
  3. N-1号灯的开关只能影响N-2和N-1位置的灯

N栈灯排成一个圈:

  1. i为中间位置时,i号灯的开关能影响i-1、i和i+1
  2. 0号灯的开关能影响N-1、0和1位置的灯
  3. N-1号灯的开关能影响N-2、N-1和0位置的灯

从左到右的尝试模型

这个从左到右的尝试模型跟之前的不一样,因为中间的灯会影响到左右两边的灯(不固定),也会影响自己。

定义函数f(i,p,c) :下一个位置之前的状态当前的状态

  1. i 代表当前位置的下一个位置
  2. i-1 代表当前位置
  3. p 代表当前位置前一个位置 i-2 的状态
  4. c 代表当前位置的状态

例如:arr[0,1,1,0...]

  1. 0位置按了开关,0=>1

    来到1位置,i代表下一个位置,所以i = 2,之前的状态,0按了开关,所以变成了1,当前状态由原来的1变成了0,所以f函数应该是 f(2,1,0)

  2. 0位置不按开关

    f(2,0,1)

二、实现

    public static int noLoopMinStep(int[] arr) {
        if (arr == null || arr.length == 0) {
            return 0;
        }
        if (arr.length == 1) {
            return arr[0] ^ 1;
        }
        if (arr.length == 2) {
            return arr[0] != arr[1] ? Integer.MAX_VALUE : (arr[0] ^ 1);
        }
        // 不变0位置的状态
        int p1 = process(arr, 2, arr[0], arr[1]);
        // 改变0位置的状态
        int p2 = process(arr, 2, arr[0] ^ 1, arr[1] ^ 1);
        if (p2 != Integer.MAX_VALUE) {
            p2++;
        }
        return Math.min(p1, p2);
    }

    // 当前在哪个位置上,做选择,nextIndex - 1 = cur ,当前!
    // cur - 1 preStatus
    // cur  curStatus
    // 0....cur-2  全亮的!
    public static int process(int[] arr, int nextIndex, int preStatus, int curStatus) {
        if (nextIndex == arr.length) { // 当前来到最后一个开关的位置
            return preStatus != curStatus ? (Integer.MAX_VALUE) : (curStatus ^ 1);
        }
        // 没到最后一个按钮呢!
        // i < arr.length
        if (preStatus == 0) { // 一定要改变
            curStatus ^= 1;
            int cur = arr[nextIndex] ^ 1;
            int next = process(arr, nextIndex + 1, curStatus, cur);
            return next == Integer.MAX_VALUE ? next : (next + 1);
        } else { // 一定不能改变
            return process(arr, nextIndex + 1, curStatus, arr[nextIndex]);
        }
    }

三、总结

两个递归里边只有执行一个,可以进行进一步优化,参数复用!

问题二有些难!!!