leetcode-灯泡开关 Ⅱ

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode-灯泡开关 Ⅱ相关的知识,希望对你有一定的参考价值。

参考技术A 现有一个房间,墙上挂有 n 只已经打开的灯泡和 4 个按钮。在进行了 m 次未知操作后,你需要返回这 n 只灯泡可能有多少种不同的状态。

假设这 n 只灯泡被编号为 [1, 2, 3 ..., n],这 4 个按钮的功能如下:

将所有灯泡的状态反转(即开变为关,关变为开)
将编号为偶数的灯泡的状态反转
将编号为奇数的灯泡的状态反转
将编号为 3k+1 的灯泡的状态反转(k = 0, 1, 2, ...)
示例 1:

输入: n = 1, m = 1.
输出: 2
说明: 状态为: [开], [关]
示例 2:

输入: n = 2, m = 1.
输出: 3
说明: 状态为: [开, 关], [关, 开], [关, 关]
示例 3:

输入: n = 3, m = 1.
输出: 4
说明: 状态为: [关, 开, 关], [开, 关, 开], [关, 关, 关], [关, 开, 开].
注意: n 和 m 都属于 [0, 1000].

算法:

因为前 6 个灯唯一地决定了其余的灯。这是因为修改第 xx 灯光的每个操作都会修改 第 (x+6)(x+6) 灯光,因此 xx 灯光始终等于 (x+6)(x+6) 灯光。
实际上,前 3 个灯唯一地确定了序列的其余部分,如下表所示,用于执行操作 a, b, c, d:

Light 1 = 1 + a + c + d
Light 2 = 1 + a + b
Light 3 = 1 + a + c
Light 4 = 1 + a + b + d
Light 5 = 1 + a + c
Light 6 = 1 + a + b
上述理由表明,在不损失一般性的情况下,取 n = min(n, 3)n=min(n,3) 是合理的。
让我们用 (a, b, c)(a,b,c) 来表示灯的状态。与值为 (1, 1, 1), (0, 1, 0), (1, 0, 1),(1,1,1),(0,1,0),(1,0,1), (1, 0, 0)(1,0,0) xor.
当 m=0m=0 时,所有灯都亮起,只有一个状态 (1, 1, 1)(1,1,1)。在这种情况下,答案总是 1。
当 m=1m=1 时,我们可以得到状态 (0, 0, 0)(0,0,0), (1, 0, 1)(1,0,1), (0, 1, 0)(0,1,0), (0, 1, 1)(0,1,1)。在这种情况下,对于 n = 1, 2, 3n=1,2,3 的答案是 2, 3, 4。
当 m=2m=2 时,我们可以检查是否可以获得 7 个状态:除(0, 1, 1)(0,1,1)之外的所有状态。在这种情况下,n = 1, 2, 3n=1,2,3 的答案是 2, 4, 7
当 m=3m=3 时,我们可以得到所有 8 个状态。在这种情况下,n = 1, 2, 3n=1,2,3 的答案是 2, 4, 8

复杂度分析

时空复杂性:O(1)O(1)。整个程序使用常量。

LeetCode 520. 检测大写字母 / 677. 键值映射 / 319. 灯泡开关

520. 检测大写字母

2021.11.13 每日一题

题目描述

我们定义,在以下情况时,单词的大写用法是正确的:

  • 全部字母都是大写,比如 “USA” 。
  • 单词中所有字母都不是大写,比如 “leetcode” 。
  • 如果单词不只含有一个字母,只有首字母大写, 比如 “Google” 。

给你一个字符串 word 。如果大写用法正确,返回 true ;否则,返回 false 。

示例 1:

输入:word = “USA”
输出:true

示例 2:

输入:word = “FlaG”
输出:false

提示:

1 <= word.length <= 100
word 由小写和大写英文字母组成

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/detect-capital
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

简单题,就简单处理了
学一下这两个判断大小写的方法

class Solution {
    public boolean detectCapitalUse(String word) {
        int l = word.length();
        if(l == 1)
            return true;
        //如果第一个是小写,第二个大写,直接false
        if(Character.isLowerCase(word.charAt(0)) && Character.isUpperCase(word.charAt(1)))
            return false;
        //剩下的情况,只有除了第一个字符的所有字符都是同样的,才正确
        //学一下官解,用异或判断
        for(int i = 2; i < l; i++){
            if(Character.isLowerCase(word.charAt(i)) ^ Character.isLowerCase(word.charAt(1)))
                return false;
        }
        return true;
    }
}

677. 键值映射

2021.11.14 每日一题

题目描述

实现一个 MapSum 类,支持两个方法,insert 和 sum:

  • MapSum() 初始化 MapSum 对象
  • void insert(String key, int val) 插入 key-val 键值对,字符串表示键 key ,整数表示值 val 。如果键 key 已经存在,那么原来的键值对将被替代成新的键值对。
  • int sum(string prefix) 返回所有以该前缀 prefix 开头的键 key 的值的总和。

示例:

输入:
[“MapSum”, “insert”, “sum”, “insert”, “sum”]
[[], [“apple”, 3], [“ap”], [“app”, 2], [“ap”]]
输出:
[null, null, 3, null, 5]
解释:
MapSum mapSum = new MapSum();
mapSum.insert(“apple”, 3);
mapSum.sum(“ap”); // return 3 (apple = 3)
mapSum.insert(“app”, 2);
mapSum.sum(“ap”); // return 5 (apple + app = 3 + 2 = 5)

提示:

1 <= key.length, prefix.length <= 50
key 和 prefix 仅由小写英文字母组成
1 <= val <= 1000
最多调用 50 次 insert 和 sum

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/map-sum-pairs
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

因为字符串不多,字符串长度也不长,所以直接存储每一个前缀就OK
可以将哈希表换成字典树

class MapSum {
    Map<String, Integer> smap;
    Map<String, Integer> premap;
    public MapSum() {
        smap = new HashMap<>();
        premap = new HashMap<>();
    }
    
    public void insert(String key, int val) {
        int last = smap.getOrDefault(key, 0);
        smap.put(key, val);
        for(int i = 0; i < key.length(); i++){
            String temp = key.substring(0, i + 1);
            premap.put(temp, premap.getOrDefault(temp, 0) - last + val);
        }
    }
    
    public int sum(String prefix) {
        return premap.containsKey(prefix) ? premap.get(prefix) : 0;
    }
}

/**
 * Your MapSum object will be instantiated and called as such:
 * MapSum obj = new MapSum();
 * obj.insert(key,val);
 * int param_2 = obj.sum(prefix);
 */

本来不想写字典树了,想了一下,还是再练一下吧

class MapSum {
    class Trie{
        int val;
        Trie[] node = new Trie[26];
    }
    Map<String, Integer> map;
    Trie trie;

    public MapSum() {
        map = new HashMap<>();
        trie = new Trie();
    }
    
    public void insert(String key, int val) {
        int last = map.getOrDefault(key, 0);
        Trie root = trie;
        map.put(key, val);
        for(int i = 0; i < key.length(); i++){
            char c = key.charAt(i);
            if(root.node[c - 'a'] == null)
                root.node[c - 'a'] = new Trie();
            root = root.node[c - 'a'];
            root.val += val - last;
        }
    }
    
    public int sum(String prefix) {
        Trie root = trie;
        for(char c : prefix.toCharArray()){
            if(root.node[c - 'a'] == null)
                return 0;
            else{
                root = root.node[c - 'a'];
            }
        }
        return root.val;
    }
}

/**
 * Your MapSum object will be instantiated and called as such:
 * MapSum obj = new MapSum();
 * obj.insert(key,val);
 * int param_2 = obj.sum(prefix);
 */

319. 灯泡开关

2021.11.15 每日一题

题目描述

初始时有 n 个灯泡处于关闭状态。第一轮,你将会打开所有灯泡。接下来的第二轮,你将会每两个灯泡关闭一个。

第三轮,你每三个灯泡就切换一个灯泡的开关(即,打开变关闭,关闭变打开)。第 i 轮,你每 i 个灯泡就切换一个灯泡的开关。直到第 n 轮,你只需要切换最后一个灯泡的开关。

找出并返回 n 轮后有多少个亮着的灯泡。

示例 1:


输入:n = 3
输出:1
解释:
初始时, 灯泡状态 [关闭, 关闭, 关闭].
第一轮后, 灯泡状态 [开启, 开启, 开启].
第二轮后, 灯泡状态 [开启, 关闭, 开启].
第三轮后, 灯泡状态 [开启, 关闭, 关闭].
你应该返回 1,因为只有一个灯泡还亮着。

示例 2:

输入:n = 0
输出:0

示例 3:

输入:n = 1
输出:1

提示:

0 <= n <= 10^9

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/bulb-switcher
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

想到因数,然后想到除了平方数,其他因数都是成对的,就领悟到真谛了

class Solution {
    public int bulbSwitch(int n) {
        //首先必须弄清楚提题意,先试试,应该就是第i个变化
        //试一下4,也就是第二轮,1 0 1 0;第三轮,1 0 0 0;第四轮 1 0 0 1,所以2
        //5, 1 0 1 0 1;第三轮,1 0 0 0 1; 第四轮,1 0 0 1 1,第五轮,1 0 0 1 0
        //6, 101010;100011;100111;100101;100100
        //7,1010101;1000111;1001111;1001011;1001001;1001000
        //8,10101010;10001110;10011111;10010111;10010000..
        //9,101010101;100011100;100111110;100100001
        //10,1001000010;11,10010000100;12,100100001000;13,1001000010000;14,10010000100000;
        //15,100100001000000;16,1001000010000001;17,18,
        //想想,有什么规律,就是看每个位置变了几次吗
        //也就是说每个数有多少个因数?但是这也太麻烦了,肯定过不了
        //举了这么多例子,终于想到了,因数有几个呢,如果是平方数,那么就会有偶数个公因数,所以这个位置的灯泡就是亮的
        //而其他位置,由于因数是成对的,所以就会熄灭
        long num = n;
        long i = 1;
        while(i * i <= n){
            i++;
        }
        return (int)(i - 1);
    }
}

以上是关于leetcode-灯泡开关 Ⅱ的主要内容,如果未能解决你的问题,请参考以下文章

Leetcode 672.灯泡开关II

LeetCode 319 灯泡开关[数学] HERODING的LeetCode之路

LeetCode 672 灯泡开关II[找规律 数学] HERODING的LeetCode之路

[LeetCode]319. Bulb Switcher灯泡开关

LeetCode 520. 检测大写字母 / 677. 键值映射 / 319. 灯泡开关

LeetCode_Nov_3rd_Week