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 319 灯泡开关[数学] HERODING的LeetCode之路
LeetCode 672 灯泡开关II[找规律 数学] HERODING的LeetCode之路
[LeetCode]319. Bulb Switcher灯泡开关