LeetCode690,137(只出现一次数字合集),剑指20,有限状态自动机
Posted Zephyr丶J
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode690,137(只出现一次数字合集),剑指20,有限状态自动机相关的知识,希望对你有一定的参考价值。
LeetCode 690 员工的重要性
2021.5.1的每日一题,简单题,思路也比较简单,就是将员工存储起来,然后按照要求查询就行了,因为下属可能还有下属,所以需要递归或者迭代,自己写的代码
class Solution {
public int getImportance(List<Employee> employees, int id) {
//先遍历列表存储每个员工的编号和对应的下标,然后查询
Map<Integer, Integer> map = new HashMap<>();
for(int i = 0; i < employees.size(); i++){
map.put(employees.get(i).id, i);
}
int res = 0;
Employee leadall = employees.get(map.get(id));
//当下属不为空
Deque<Employee> stack = new LinkedList<>();
stack.push(leadall);
while(!stack.isEmpty()){
Employee lead = stack.pop();
List<Integer> sub = lead.subordinates;
res += lead.importance;
for(int i = 0; i < sub.size(); i++){
//sub中找下属的id,然后在map中找id的下标,在employees中找下标对应的下属
Employee temp = employees.get(map.get(sub.get(i)));
stack.push(temp);
}
}
return res;
}
}
然后看了解答,发现map中存id和员工更简单;另外,我这里是用的栈,因为我写的时候没有想到什么深度广度,只是觉得栈可以实现。而一般广度有限遍历是用队列,这里没有区别,不过以后还是要注意
LeetCode 137(只出现一次数字合集)
昨天的每日一题,我能想到的只有统计个数,主要学习二进制写法和有限状态自动机,二进制代码如下:
class Solution {
public int singleNumber(int[] nums) {
//出现两次异或就行了,三次咋整呢,我想到的只有统计个数
//看了二进制,直呼好家伙
//统计每一个数的32个二进制位上的个数,因为非答案数有三个,所以说三个加起来肯定是0或者3
//而答案数,是1或者0,那么统计所有数的第一位1的个数,然后余3,得到的数就是答案该位是否为1
int res = 0;
for(int i = 0; i < 32; i++){
int total = 0;
for(int num : nums){
total += ((num >> i) & 1);
}
res = ((total % 3) << i) | res;
}
return res;
}
}
另外就是有限状态自动机了,官解里面叫数字电路的设计
这个也是按位处理,按位统计每个数字该位上的数字,只不过使用状态转移的方法进行统计的,因为每个数字出现的个数是3次,所以3个状态00 01 02,然后每出现一次就进行状态的转移,而只出现了一次的数字就会让该二进制位是1,这样就可以找出这个数字了。很巧妙,感觉一般想不出来
关键问题就是如何写状态转移的代码,昨天在这里卡了很久,之前也学过数电,而且好像还学的不错,但是现在也真是忘了。最后去看了一篇文章,大概了解了一下如何用真值表写出表达式
先列出真值表,这一步应该不难,然后根据真值表中最后结果为1的状态,将前面的状态一个个用表达式写出来,然后相或,也就是+,就可以了。当然也可以根据结果为0的状态写
另外这里有个地方也要注意,就是因为是高位和低位两个状态都要转移,所以同时转移和先转移低位再转移高位的表达式是不同的。同时转移的时候要用临时变量存储
最后输出的时候,高位是0,因此只输出低位就可以
class Solution {
public int singleNumber(int[] nums) {
//看了半天,终于差不多能看懂个状态机的大概了,什么个意思呢
//就是对于每一个数,也是按位处理,就和刚刚的二进制是一样的
//但是吧,这里有变化的地方就是统计每位的个数的方法
//状态机使用三个数00 01 02 来统计每一位的个数,因为二进制数02使用10表示的,所以用两个数ab分别代表高位和低位
//三个状态循环转变,00->01->10->00
//那么如何转变呢,这就可以写出一个真值表,然后总结出转变的公式
//这样,32位就可以同时进行计算了
//主要还是推转变公式
//对于低位来说,当高位为1,碰到0或者1都是0;高位为0,碰到1,变1,碰到0不变
//写成公式就是b = b ^ x & ~a (当a等于1时,就是0,;当a等于0时,看左边一项)
//再看高位,此时低位已经发生了变化,因此要在低位变化的基础上计算高位,这个想不通了
//此时如果b是1,那么之前b可能是0或者1,不管x是0还是1,此时a不变,都是0;如果b此时是0,那么之前a可能是0或者1,
//如果x是0,那么b就是00变00或者10变10,那么a就是0或者1,如果x是1,那么b就是01变10,那么a就是1
//这个是同时变化的,用临时变量存储
//主要是列出真值表,然后根据结果为1的情况写出表达式
int a = 0, b = 0;
for (int num : nums) {
int aNext = (~a & b & num) | (a & ~b & ~num), bNext = ~a & (b ^ num);
a = aNext;
b = bNext;
}
return b;
//这个理解过程是先计算低位,再根据变化后的低位计算高位
int a = 0, b = 0;
for(int num : nums){
a = a ^ num & ~b;
b = b ^ num & ~a;
}
return a;
}
}
剑指Offer20 表示数值的字符串
下午正好看到这个题了,发现又是有限状态自动机,巧了
这个题状态其实好想多了,就是按照题目的描述,把每一步都定义一个状态,然后根据组成一个数的规则,进行状态的转移。遍历所给的字符串,根据定义的规则进行状态转移,如果不能转移或者到最后不是一个数值的结尾,那么就说明不能表示数值,false
这里直接复制了Krahets,K神的代码,学习一下,加了点注释
class Solution {
//很有意思的一道题目,今天上午刚用了状态机,就看到这道题目了,说白了,就是定义状态,然后根据遍历到的字符进行状态的转移
public boolean isNumber(String s) {
Map[] states = {
new HashMap<>() {{ put(' ', 0); put('s', 1); put('d', 2); put('.', 4); }}, // 0. 表示空格后面可以是空格,+-,数字,小数点
new HashMap<>() {{ put('d', 2); put('.', 4); }}, // 1. 表示+-后面可以跟数字和小数点
new HashMap<>() {{ put('d', 2); put('.', 3); put('e', 5); put(' ', 8); }}, // 2. 小数点前的数字
new HashMap<>() {{ put('d', 3); put('e', 5); put(' ', 8); }}, // 3. 小数点
new HashMap<>() {{ put('d', 3); }}, // 4. 空格直接跟小数点和小数点后的数字
new HashMap<>() {{ put('s', 6); put('d', 7); }}, // 5. e
new HashMap<>() {{ put('d', 7); }}, // 6. e后面的+-号
new HashMap<>() {{ put('d', 7); put(' ', 8); }}, // 7. 整数数字
new HashMap<>() {{ put(' ', 8); }} // 8. 最后的空格
};
//表示第几个状态,刚开始定义为空格
int p = 0;
char t;
for(char c : s.toCharArray()) {
//遍历字符,用t表示当前状态是什么,d是数字,s是+-符号,e是阶次
if(c >= '0' && c <= '9') t = 'd';
else if(c == '+' || c == '-') t = 's';
else if(c == 'e' || c == 'E') t = 'e';
else if(c == '.' || c == ' ') t = c;
else t = '?';
//如果当前所在的状态中有这个字符,那么就进行转移,没有就返回false
if(!states[p].containsKey(t)) return false;
p = (int)states[p].get(t);
}
//最终以这几个状态结尾的就是一个可以表示数值的字符串
return p == 2 || p == 3 || p == 7 || p == 8;
}
}
另外,还有两种思路,就是剑指Offer提供的思路和逐一判断的思路,其实剑指Offer也相当于逐一判断,这里就不贴了
以上是关于LeetCode690,137(只出现一次数字合集),剑指20,有限状态自动机的主要内容,如果未能解决你的问题,请参考以下文章