[LeetCode] Bulb Switcher II 灯泡开关之二

There is a room with n lights which are turned on initially and 4 buttons on the wall. After performing exactly m unknown operations towards buttons, you need to return how many different kinds of status of the n lights could be.

Suppose n lights are labeled as number [1, 2, 3 ..., n], function of these 4 buttons are given below:

  1. Flip all the lights.
  2. Flip lights with even numbers.
  3. Flip lights with odd numbers.
  4. Flip lights with (3k + 1) numbers, k = 0, 1, 2, ...

Example 1:

Input: n = 1, m = 1.
Output: 2
Explanation: Status can be: [on], [off]

Example 2:

Input: n = 2, m = 1.
Output: 3
Explanation: Status can be: [on, off], [off, on], [off, off] 

Example 3:

Input: n = 3, m = 1.
Output: 4
Explanation: Status can be: [off, on, off], [on, off, on], [off, off, off], [off, on, on].

Note: n and m both fit in range [0, 1000].

这道题是之前那道Bulb Switcher的拓展,但是关灯的方式改变了。现在有四种关灯方法,全关,关偶数灯,关奇数灯,关3k+1的灯。现在给我们n盏灯,允许m步操作,问我们总共能组成多少种不同的状态。博主开始想,题目没有让列出所有的情况,而只是让返回总个数。那么博主觉得应该不能用递归的暴力破解来做,一般都是用DP来做啊。可是想了半天也没想出递推公式,只得作罢。只好去参考大神们的做法,发现这道题的结果并不会是一个超大数,最多情况只有8种。转念一想,也是,如果结果是一个超大数,一般都会对一个超大数10e7来取余,而这道题并没有,所以是一个很大的hint,只不过博主没有get到。博主应该多列几种情况的,说不定就能找出规律。下面先来看一种暴力解法,首先我们先做一个小小的优化,我们来分析四种情况:

第一种情况:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,...

第二种情况:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,...

第三种情况:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,...

第四种情况:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,...

通过观察上面的数组,我们可以发现以6个为1组,都是重复的pattern,那么实际上我们可以把重复的pattern去掉而且并不会影响结果。如果n大于6,我们则对其取余再加上6,新的n跟使用原来的n会得到同样的结果,但这样降低了我们的计算量。

下面我们先来生成n个1,这里1表示灯亮,0表示灯灭,然后我们需要一个set来记录已经存在的状态,用一个queue来辅助我们的BFS运算。我们需要循环m次,因为要操作m次,每次开始循环之前,先统计出此时queue中数字的个数len,然后进行len次循环,这就像二叉树中的层序遍历,必须上一层的结点全部遍历完了才能进入下一层,当然,在每一层开始前,我们都需要情况集合s,这样每个操作之间才不会互相干扰。然后在每层的数字循环中,我们取出队首状态,然后分别调用四种方法,突然感觉,这很像迷宫遍历问题,上下左右四个方向,周围四个状态算出来,我们将不再集合set中的状态加入queue和集合set。当m次操作遍历完成后,队列queue中状态的个数即为所求,参见代码如下:

解法一:

class Solution {
public:
    int flipLights(int n, int m) {
        n == (n <= 6) ? n : (n % 6 + 6);
        int start = (1 << n) - 1;
        unordered_set<int> s;
        queue<int> q{{start}};
        for (int i = 0; i < m; ++i) {
            int len = q.size();
            s.clear();
            for (int k = 0; k < len; ++k) {
                int t = q.front(); q.pop();
                vector<int> next{flipAll(t, n), flipEven(t, n), flipOdd(t, n), flip3k1(t, n)};
                for (int num : next) {
                    if (s.count(num)) continue;
                    q.push(num);
                    s.insert(num);
                }
            }
        }
        return q.size();
    }

    int flipAll(int t, int n) {
        int x = (1 << n) - 1;
        return t ^ x;
    }

    int flipEven(int t, int n) {
        for (int i = 0; i < n; i += 2) {
            t ^= (1 << i);
        }
        return t;
    }

    int flipOdd(int t, int n) {
        for (int i = 1; i < n; i += 2) {
            t ^= (1 << i);
        }
        return t;
    }

    int flip3k1(int t, int n) {
        for (int i = 0; i < n; i += 3) {
            t ^= (1 << i);
        }
        return t;
    }
};

 

上面那个方法虽然正确,但是有些复杂了,由于这道题最多只有8中情况,所以很适合分情况来讨论:

- 当m和n其中有任意一个数是0时,返回1

- 当n = 1时

只有两种情况,0和1

- 当n = 2时,

这时候要看m的次数,如果m = 1,那么有三种状态 00,01,10

当m > 1时,那么有四种状态,00,01,10,11

- 当m = 1时,

此时n至少为3,那么我们有四种状态,000,010,101,011

- 当m = 2时,

此时n至少为3,我们有七种状态:111,101,010,100,000,001,110

- 当m > 2时,

此时n至少为3,我们有八种状态:111,101,010,100,000,001,110,011

 

解法二:

class Solution {

public:
    int flipLights(int n, int m) {
        if (n == 0 || m == 0) return 1;
        if (n == 1) return 2;
        if (n == 2) return m == 1 ? 3 : 4;
        if (m == 1) return 4;
        return m == 2 ? 7 : 8;
    }
};

下面这种简洁到变态的方法是史蒂芬大神观察规律得到的,他自己也在帖子中说不清为啥这样可以,但是就是叼,贴上来纯属娱乐吧~ 

解法三:

class Solution {
public:
    int flipLights(int n, int m) {
        n = min(n, 3);
        return min(1 << n, 1 + m * n);
    }
};

参考资料:

https://discuss.leetcode.com/topic/102022/c-concise-code-o-1

https://discuss.leetcode.com/topic/102395/2-short-lines-simple-formula

https://discuss.leetcode.com/topic/102227/short-and-clean-java-o-1-solution

https://discuss.leetcode.com/topic/102107/easy-to-understand-java-bfs-solution-o-m

本文转自博客园Grandyang的博客,原文链接:[LeetCode] Bulb Switcher II 灯泡开关之二

,如需转载请自行联系原博主。

时间: 2024-08-01 15:31:39

[LeetCode] Bulb Switcher II 灯泡开关之二的相关文章

[LeetCode] Beautiful Arrangement II 优美排列之二

Given two integers n and k, you need to construct a list which contains n different positive integers ranging from 1 to n and obeys the following requirement:  Suppose this list is [a1, a2, a3, ... , an], then the list [|a1 - a2|, |a2 - a3|, |a3 - a4

[LeetCode] Decode Ways II 解码方法之二

A message containing letters from A-Z is being encoded to numbers using the following mapping way: 'A' -> 1 'B' -> 2 ... 'Z' -> 26 Beyond that, now the encoded string can also contain the character '*', which can be treated as one of the numbers

[LeetCode] My Calendar II 我的日历之二

Implement a MyCalendarTwo class to store your events. A new event can be added if adding the event will not cause a triple booking. Your class will have one method, book(int start, int end). Formally, this represents a booking on the half open interv

[LeetCode] Sentence Similarity II 句子相似度之二

Given two sentences words1, words2 (each represented as an array of strings), and a list of similar word pairs pairs, determine if two sentences are similar. For example, words1 = ["great", "acting", "skills"] and words2 = [&

[LeetCode] Valid Palindrome II 验证回文字符串之二

Given a non-empty string s, you may delete at most one character. Judge whether you can make it a palindrome. Example 1: Input: "aba" Output: True Example 2: Input: "abca" Output: True Explanation: You could delete the character 'c'. N

imageview-如何用Switch控件控制Imageview改变图片达到灯泡开关的效果

问题描述 如何用Switch控件控制Imageview改变图片达到灯泡开关的效果 light1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked){ imageView1.setBackgroundR

[LeetCode]90.Subsets II

题目 Given a collection of integers that might contain duplicates, S, return all possible subsets. Note: Elements in a subset must be in non-descending order. The solution set must not contain duplicate subsets. For example, If S = [1,2,2], a solution

[LeetCode]--47. Permutations II

Given a collection of numbers that might contain duplicates, return all possible unique permutations. For example, [1,1,2] have the following unique permutations: [ [1,1,2], [1,2,1], [2,1,1] ] [LeetCode]–46. Permutations 我觉得跟46题没有区别,说是unique不过上一题也是un

[LeetCode] Contains Duplicate(II,III)

Contains Duplicate Given an array of integers, find if the array contains any duplicates. Your function should return true if any value appears at least twice in the array, and it should return false if every element is distinct. 解题思路 用一个set保存数组中的值,如