360内推笔试编程题2017
360笔试编程题一共三道:360春招&实习生招聘3.25在线编程题解
第一题是给出根据数学期望的公式编程实现,需要注意的是结果要求四舍五入保留三位小数,详情见链接。
第二题是求给定的字符串的子串中偶串的个数,偶串是指字符串中每个字母出现的次数均为偶数。
一种思路:
遍历所有子串,判断每个子串是否为偶串,判断方法为:建一个map,遍历子串的每个字符,遍历到某个字符时,判断map中是否包含该字符,如果不包含就以该字符为key将它put进去,如果包含就将它移除。某次循环结束时,如果map为空,则表示这个子串为偶串。
/* 代码如下 */ public int evenSubStringNum(String s) { if (s == null) { return 0; } Map<Character, Character> map = new HashMap<>(); char[] charArr = s.toCharArray(); int sum = 0; for (int i = 0; i < charArr.length; i++) { for (int j = i; j < charArr.length; j++) { if (!map.containsKey(charArr[j])) { map.put(charArr[j], charArr[j]); } else { map.remove(charArr[j]); } if (map.isEmpty()) { sum++; } } map.clear(); } return sum; }
上述解法时间复杂度较高,笔试结束后在赛码网上看到了更优的解法,利用异或运算符求解,C++代码如下:
#include <bits/stdc++.h> #define maxn 100009 using namespace std; char s[maxn]; map<int,int>mp; int n; int main(){ scanf("%s",s); n = strlen(s); mp[0] = 1; int cur = 0; long long ans = 0; for(int i = 0; i < n; i++){ int x = s[i] - 'a'; cur ^= (1 << x); ans += mp[cur]; mp[cur]++; } cout << ans << endl; return 0; }
自己转换成Java代码如下:
public int evenSubStrings(String s) { Map<Integer, Integer> map = new HashMap<>(); char[] chars = s.toCharArray(); int n = chars.length; int cur = 0; int ans = 0; map.put(0, 1); for (int i = 0; i < n; i++) { int x = chars[i] - 'a'; cur ^= (1 << x); ans += map.get(cur) == null ? 0 : map.get(cur); if (map.get(cur) == null) { map.put(cur, 1); } else { map.put(cur, map.get(cur)+1); } } return ans; }
没有看懂,在评论里见到了一个解释,摘抄如下:
我来解释一下第二题好了,,,扫一遍记录下每个前缀子串的状态(每个字母出现的次数为奇/偶)。如果两个前缀状态相同,说明夹在它们中间的子串肯定是个偶串。我是组合数算的,相同状态的前缀两两组合都是一个偶串,像题解里每次相加也行。
因为只有26个字母,所以可以状态压缩,用 32 位 int 的其中 26 位来记录状态,某位为 0 表示 该位对应的字母为偶数。
1<<26的状态数太大了所以用map存。注意有个坑是mp[0] = 1,不然20%会挂掉。