From b8fb9c33cee0e0c30233f13c73ed7aa874b26f0f Mon Sep 17 00:00:00 2001 From: CyC2018 <1029579233@qq.com> Date: Mon, 18 Jun 2018 12:05:06 +0800 Subject: [PATCH] auto commit --- notes/2016 校招真题题解.md | 742 ------------------------------------- 1 file changed, 742 deletions(-) delete mode 100644 notes/2016 校招真题题解.md diff --git a/notes/2016 校招真题题解.md b/notes/2016 校招真题题解.md deleted file mode 100644 index da6709ab..00000000 --- a/notes/2016 校招真题题解.md +++ /dev/null @@ -1,742 +0,0 @@ - -* [前言](#前言) -* [1. 小米-小米Git](#1-小米-小米git) -* [2. 小米-懂二进制](#2-小米-懂二进制) -* [3. 小米-中国牛市](#3-小米-中国牛市) -* [4. 微软-LUCKY STRING](#4-微软-lucky-string) -* [5. 微软-Numeric Keypad](#5-微软-numeric-keypad) -* [6. 微软-Spring Outing](#6-微软-spring-outing) -* [7. 微软-S-expression](#7-微软-s-expression) -* [8. 华为-最高分是多少](#8-华为-最高分是多少) -* [9. 华为-简单错误记录](#9-华为-简单错误记录) -* [10. 华为-扑克牌大小](#10-华为-扑克牌大小) -* [11. 去哪儿-二分查找](#11-去哪儿-二分查找) -* [12. 去哪儿-首个重复字符](#12-去哪儿-首个重复字符) -* [13. 去哪儿-寻找Coder](#13-去哪儿-寻找coder) -* [14. 美团-最大差值](#14-美团-最大差值) -* [15. 美团-棋子翻转](#15-美团-棋子翻转) -* [16. 美团-拜访](#16-美团-拜访) -* [17. 美团-直方图内最大矩形](#17-美团-直方图内最大矩形) -* [18. 美团-字符串计数](#18-美团-字符串计数) -* [19. 美团-平均年龄](#19-美团-平均年龄) -* [20. 百度-罪犯转移](#20-百度-罪犯转移) -* [22. 百度-裁减网格纸](#22-百度-裁减网格纸) -* [23. 百度-钓鱼比赛](#23-百度-钓鱼比赛) -* [24. 百度-蘑菇阵](#24-百度-蘑菇阵) - - - -# 前言 - -省略的代码: - -```java -import java.util.*; -``` - -```java -public class Solution { -} -``` - -```java -public class Main { - public static void main(String[] args) { - Scanner in = new Scanner(System.in); - while (in.hasNext()) { - } - } -} -``` - -# 1. 小米-小米Git - -- 重建多叉树 -- 使用 LCA - -```java -private class TreeNode { - int id; - List childs = new ArrayList<>(); - - TreeNode(int id) { - this.id = id; - } -} - -public int getSplitNode(String[] matrix, int indexA, int indexB) { - int n = matrix.length; - boolean[][] linked = new boolean[n][n]; // 重建邻接矩阵 - for (int i = 0; i < n; i++) { - for (int j = 0; j < n; j++) { - linked[i][j] = matrix[i].charAt(j) == '1'; - } - } - TreeNode tree = constructTree(linked, 0); - TreeNode ancestor = LCA(tree, new TreeNode(indexA), new TreeNode(indexB)); - return ancestor.id; -} - -private TreeNode constructTree(boolean[][] linked, int root) { - TreeNode tree = new TreeNode(root); - for (int i = 0; i < linked[root].length; i++) { - if (linked[root][i]) { - linked[i][root] = false; // 因为题目给的邻接矩阵是双向的,在这里需要把它转为单向的 - tree.childs.add(constructTree(links, i)); - } - } - return tree; -} - -private TreeNode LCA(TreeNode root, TreeNode p, TreeNode q) { - if (root == null || root.id == p.id || root.id == q.id) return root; - TreeNode ancestor = null; - int cnt = 0; - for (int i = 0; i < root.childs.size(); i++) { - TreeNode tmp = LCA(root.childs.get(i), p, q); - if (tmp != null) { - ancestor = tmp; - cnt++; - } - } - return cnt == 2 ? root : ancestor; -} -``` - -# 2. 小米-懂二进制 - -对两个数进行异或,结果的二进制表示为 1 的那一位就是两个数不同的位。 - -```java -public int countBitDiff(int m, int n) { - return Integer.bitCount(m ^ n); -} -``` - -# 3. 小米-中国牛市 - -背包问题,可以设一个大小为 2 的背包。 - -状态转移方程如下: - -```html -dp[i, j] = max(dp[i, j-1], prices[j] - prices[jj] + dp[i-1, jj]) { jj in range of [0, j-1] } = max(dp[i, j-1], prices[j] + max(dp[i-1, jj] - prices[jj])) -``` - -```java -public int calculateMax(int[] prices) { - int n = prices.length; - int[][] dp = new int[3][n]; - for (int i = 1; i <= 2; i++) { - int localMax = dp[i - 1][0] - prices[0]; - for (int j = 1; j < n; j++) { - dp[i][j] = Math.max(dp[i][j - 1], prices[j] + localMax); - localMax = Math.max(localMax, dp[i - 1][j] - prices[j]); - } - } - return dp[2][n - 1]; -} -``` - -# 4. 微软-LUCKY STRING - -- 斐波那契数列可以预计算; -- 从头到尾遍历字符串的过程,每一轮循环都使用一个 Set 来保存从 i 到 j 出现的字符,并且 Set 保证了字符都不同,因此 Set 的大小就是不同字符的个数。 - -```java -Set fibSet = new HashSet<>(Arrays.asList(1, 2, 3, 5, 8, 13, 21, 34, 55, 89)); -Scanner in = new Scanner(System.in); -String str = in.nextLine(); -int n = str.length(); -Set ret = new HashSet<>(); -for (int i = 0; i < n; i++) { - Set set = new HashSet<>(); - for (int j = i; j < n; j++) { - set.add(str.charAt(j)); - int cnt = set.size(); - if (fibSet.contains(cnt)) { - ret.add(str.substring(i, j + 1)); - } - } -} -String[] arr = ret.toArray(new String[ret.size()]); -Arrays.sort(arr); -for (String s : arr) { - System.out.println(s); -} -``` - -# 5. 微软-Numeric Keypad - -```java -private static int[][] canReach = { - {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 0 - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 1 - {1, 0, 1, 1, 0, 1, 1, 0, 1, 1}, // 2 - {0, 0, 0, 1, 0, 0, 1, 0, 0, 1}, // 3 - {1, 0, 0, 0, 1, 1, 1, 1, 1, 1}, // 4 - {1, 0, 0, 0, 0, 1, 1, 0, 1, 1}, // 5 - {0, 0, 0, 0, 0, 0, 1, 0, 0, 1}, // 6 - {1, 0, 0, 0, 0, 0, 0, 1, 1, 1}, // 7 - {1, 0, 0, 0, 0, 0, 0, 0, 1, 1}, // 8 - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1} // 9 -}; - -private static boolean isLegal(char[] chars, int idx) { - if (idx >= chars.length || idx < 0) return true; - int cur = chars[idx] - '0'; - int next = chars[idx + 1] - '0'; - return canReach[cur][next] == 1; -} - -public static void main(String[] args) { - Scanner in = new Scanner(System.in); - int T = Integer.valueOf(in.nextLine()); - for (int i = 0; i < T; i++) { - String line = in.nextLine(); - char[] chars = line.toCharArray(); - for (int j = 0; j < chars.length - 1; j++) { - while (!isLegal(chars, j)) { - if (--chars[j + 1] < '0') { - chars[j--]--; - } - for (int k = j + 2; k < chars.length; k++) { - chars[k] = '9'; - } - } - } - System.out.println(new String(chars)); - } -} -``` - -# 6. 微软-Spring Outing - -下面以 N = 3,K = 4 来进行讨论。 - -初始时,令第 0 个地方成为待定地点,也就是呆在家里。 - -从第 4 个地点开始投票,每个人只需要比较第 4 个地方和第 0 个地方的优先级,里,如果超过半数的人选择了第 4 个地方,那么更新第 4 个地方成为待定地点。 - -从后往前不断重复以上步骤,不断更新待定地点,直到所有地方都已经投票。 - -上面的讨论中,先令第 0 个地点成为待定地点,是因为这样的话第 4 个地点就只需要和这个地点进行比较,而不用考虑其它情况。如果最开始先令第 1 个地点成为待定地点,那么在对第 2 个地点进行投票时,每个人不仅要考虑第 2 个地点与第 1 个地点的优先级,也要考虑与其后投票地点的优先级。 - -```java -int N = in.nextInt(); -int K = in.nextInt(); -int[][] votes = new int[N][K + 1]; -for (int i = 0; i < N; i++) { - for (int j = 0; j < K + 1; j++) { - int place = in.nextInt(); - votes[i][place] = j; - } -} -int ret = 0; -for (int place = K; place > 0; place--) { - int cnt = 0; - for (int i = 0; i < N; i++) { - if (votes[i][place] < votes[i][ret]) { - cnt++; - } - } - if (cnt > N / 2) { - ret = place; - } -} -System.out.println(ret == 0 ? "otaku" : ret); -``` - -# 7. 微软-S-expression - -# 8. 华为-最高分是多少 - -```java -int N = in.nextInt(); -int M = in.nextInt(); -int[] scores = new int[N]; -for (int i = 0; i < N; i++) { - scores[i] = in.nextInt(); -} -for (int i = 0; i < M; i++) { - String str = in.next(); - if (str.equals("U")) { - int id = in.nextInt() - 1; - int newScore = in.nextInt(); - scores[id] = newScore; - } else { - int idBegin = in.nextInt() - 1; - int idEnd = in.nextInt() - 1; - int ret = 0; - if (idBegin > idEnd) { - int t = idBegin; - idBegin = idEnd; - idEnd = t; - } - for (int j = idBegin; j <= idEnd; j++) { - ret = Math.max(ret, scores[j]); - } - System.out.println(ret); - } -} -``` - -# 9. 华为-简单错误记录 - -```java -HashMap map = new LinkedHashMap<>(); -while (in.hasNextLine()) { - String s = in.nextLine(); - String key = s.substring(s.lastIndexOf('\\') + 1); - map.put(key, map.containsKey(key) ? map.get(key) + 1 : 1); -} -List> list = new LinkedList<>(map.entrySet()); -Collections.sort(list, (o1, o2) -> o2.getValue() - o1.getValue()); -for (int i = 0; i < 8 && i < list.size(); i++) { - String[] token = list.get(i).getKey().split(" "); - String filename = token[0]; - String line = token[1]; - if (filename.length() > 16) filename = filename.substring(filename.length() - 16); - System.out.println(filename + " " + line + " " + list.get(i).getValue()); -} -``` - -# 10. 华为-扑克牌大小 - -```java -public class Main { - - private Map map = new HashMap<>(); - - public Main() { - map.put("3", 0); - map.put("4", 1); - map.put("5", 2); - map.put("6", 3); - map.put("7", 4); - map.put("8", 5); - map.put("9", 6); - map.put("10", 7); - map.put("J", 8); - map.put("Q", 9); - map.put("K", 10); - map.put("A", 11); - map.put("2", 12); - map.put("joker", 13); - map.put("JOKER ", 14); - } - - private String play(String s1, String s2) { - String[] token1 = s1.split(" "); - String[] token2 = s2.split(" "); - CardType type1 = computeCardType(token1); - CardType type2 = computeCardType(token2); - if (type1 == CardType.DoubleJoker) return s1; - if (type2 == CardType.DoubleJoker) return s2; - if (type1 == CardType.Bomb && type2 != CardType.Bomb) return s1; - if (type2 == CardType.Bomb && type1 != CardType.Bomb) return s2; - if (type1 != type2 || token1.length != token2.length) return "ERROR"; - for (int i = 0; i < token1.length; i++) { - int val1 = map.get(token1[i]); - int val2 = map.get(token2[i]); - if (val1 != val2) return val1 > val2 ? s1 : s2; - } - return "ERROR"; - } - - private CardType computeCardType(String[] token) { - boolean hasjoker = false, hasJOKER = false; - for (int i = 0; i < token.length; i++) { - if (token[i].equals("joker")) hasjoker = true; - else if (token[i].equals("JOKER")) hasJOKER = true; - } - if (hasjoker && hasJOKER) return CardType.DoubleJoker; - int maxContinueLen = 1; - int curContinueLen = 1; - String curValue = token[0]; - for (int i = 1; i < token.length; i++) { - if (token[i].equals(curValue)) curContinueLen++; - else { - curContinueLen = 1; - curValue = token[i]; - } - maxContinueLen = Math.max(maxContinueLen, curContinueLen); - } - if (maxContinueLen == 4) return CardType.Bomb; - if (maxContinueLen == 3) return CardType.Triple; - if (maxContinueLen == 2) return CardType.Double; - boolean isStraight = true; - for (int i = 1; i < token.length; i++) { - if (map.get(token[i]) - map.get(token[i - 1]) != 1) { - isStraight = false; - break; - } - } - if (isStraight && token.length == 5) return CardType.Straight; - return CardType.Sigal; - } - - private enum CardType { - DoubleJoker, Bomb, Sigal, Double, Triple, Straight; - } - - public static void main(String[] args) { - Main main = new Main(); - Scanner in = new Scanner(System.in); - while (in.hasNextLine()) { - String s = in.nextLine(); - String[] token = s.split("-"); - System.out.println(main.play(token[0], token[1])); - } - } -} -``` - -# 11. 去哪儿-二分查找 - -对于有重复元素的有序数组,二分查找需要注意以下要点: - -- if (val <= A[m]) h = m; -- 因为 h 的赋值为 m 而不是 m - 1,因此 while 循环的条件也就为 l < h。(如果是 m - 1 循环条件为 l <= h) - -```java -public int getPos(int[] A, int n, int val) { - int l = 0, h = n - 1; - while (l < h) { - int m = l + (h - l) / 2; - if (val <= A[m]) h = m; - else l = m + 1; - } - return A[h] == val ? h : -1; -} -``` - -# 12. 去哪儿-首个重复字符 - -```java -public char findFirstRepeat(String A, int n) { - boolean[] hasAppear = new boolean[256]; - for (int i = 0; i < n; i++) { - char c = A.charAt(i); - if(hasAppear[c]) return c; - hasAppear[c] = true; - } - return ' '; -} -``` - -# 13. 去哪儿-寻找Coder - -```java -public String[] findCoder(String[] A, int n) { - List> list = new ArrayList<>(); - for (String s : A) { - int cnt = 0; - String t = s.toLowerCase(); - int idx = -1; - while (true) { - idx = t.indexOf("coder", idx + 1); - if (idx == -1) break; - cnt++; - } - if (cnt != 0) { - list.add(new Pair<>(s, cnt)); - } - } - Collections.sort(list, (o1, o2) -> (o2.getValue() - o1.getValue())); - String[] ret = new String[list.size()]; - for (int i = 0; i < list.size(); i++) { - ret[i] = list.get(i).getKey(); - } - return ret; -} - -// 牛客网无法导入 javafx.util.Pair,这里就自己实现一下 Pair 类 -private class Pair { - T t; - K k; - - Pair(T t, K k) { - this.t = t; - this.k = k; - } - - T getKey() { - return t; - } - - K getValue() { - return k; - } -} -``` - -# 14. 美团-最大差值 - -贪心策略。 - -```java -public int getDis(int[] A, int n) { - int max = 0; - int soFarMin = A[0]; - for (int i = 1; i < n; i++) { - if(soFarMin > A[i]) soFarMin = A[i]; - else max = Math.max(max, A[i]- soFarMin); - } - return max; -} -``` - -# 15. 美团-棋子翻转 - -```java -public int[][] flipChess(int[][] A, int[][] f) { - int[][] direction = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; - for (int[] ff : f) { - for (int[] dd : direction) { - int r = ff[0] + dd[0] - 1, c = ff[1] + dd[1] - 1; - if(r < 0 || r > 3 || c < 0 || c > 3) continue; - A[r][c] ^= 1; - } - } - return A; -} -``` - -# 16. 美团-拜访 - -```java -private Set paths; -private List curPath; - -public int countPath(int[][] map, int n, int m) { - paths = new HashSet<>(); - curPath = new ArrayList<>(); - for (int i = 0; i < n; i++) { - for (int j = 0; j < m; j++) { - if (map[i][j] == 1) { - map[i][j] = -1; - int[][] leftRightDirection = {{1, 0}, {-1, 0}}; - int[][] topDownDirection = {{0, 1}, {0, -1}}; - for (int[] lr : leftRightDirection) { - for (int[] td : topDownDirection) { - int[][] directions = {lr, td}; - backtracking(map, n, m, i, j, directions); - } - } - return paths.size(); - } - } - } - return 0; -} - -private void backtracking(int[][] map, int n, int m, int r, int c, int[][] directions) { - if (map[r][c] == 2) { - String path = ""; - for (int num : curPath) { - path += num; - } - paths.add(path); - return; - } - for (int i = 0; i < directions.length; i++) { - int nextR = r + directions[i][0]; - int nextC = c + directions[i][1]; - if (nextR < 0 || nextR >= n || nextC < 0 || nextC >= m || map[nextR][nextC] == -1) continue; - map[nextR][nextC] = map[nextR][nextC] == 2 ? 2 : -1; - curPath.add(nextR); - curPath.add(nextC); - backtracking(map, n, m, nextR, nextC, directions); - curPath.remove(curPath.size() - 1); - curPath.remove(curPath.size() - 1); - map[nextR][nextC] = map[nextR][nextC] == 2 ? 2 : 0; - } -} -``` - -# 17. 美团-直方图内最大矩形 - -```java -public int countArea(int[] A, int n) { - int max = 0; - for (int i = 0; i < n; i++) { - int min = A[i]; - for (int j = i; j < n; j++) { - min = Math.min(min, A[j]); - max = Math.max(max, min * (j - i + 1)); - } - } - return max; -} -``` - -# 18. 美团-字符串计数 - -字符串都是小写字符,可以把字符串当成是 26 进制。但是字典序的比较和普通的整数比较不同,是从左往右进行比较,例如 "ac" 和 "abc",字典序的比较结果为 "ac" > "abc",如果按照整数方法比较,因为 "abc" 是三位数,显然更大。 - -由于两个字符串的长度可能不想等,在 s1 空白部分和 s2 对应部分进行比较时,应该把 s1 的空白部分看成是 'a' 字符进行填充的。 - -还有一点要注意的是,s1 到 s2 长度为 leni 的字符串个数只比较前面 i 个字符。例如 'aaa' 和 'bbb' ,长度为 2 的个数为 'aa' 到 'bb' 的字符串个数,不需要考虑后面部分的字符。 - -在统计个数时,从 len1 开始一直遍历到最大合法长度,每次循环都统计长度为 i 的子字符串个数。 - -```java -String s1 = in.next(); -String s2 = in.next(); -int len1 = in.nextInt(); -int len2 = in.nextInt(); -int len = Math.min(s2.length(), len2); -int[] subtractArr = new int[len]; -for (int i = 0; i < len; i++) { - char c1 = i < s1.length() ? s1.charAt(i) : 'a'; - char c2 = s2.charAt(i); - subtractArr[i] = c2 - c1; -} -int ret = 0; -for (int i = len1; i <= len; i++) { - for (int j = 0; j < i; j++) { - ret += subtractArr[j] * Math.pow(26, i - j - 1); - } -} -System.out.println(ret - 1); -``` - -# 19. 美团-平均年龄 - -```java -int W = in.nextInt(); -double Y = in.nextDouble(); -double x = in.nextDouble(); -int N = in.nextInt(); -while (N-- > 0) { - Y++; // 老员工每年年龄都要加 1 - Y += (21 - Y) * x; -} -System.out.println((int) Math.ceil(Y)); -``` - -# 20. 百度-罪犯转移 - -部分和问题,将每次求的部分和缓存起来。 - -```java -int n = in.nextInt(); -int t = in.nextInt(); -int c = in.nextInt(); -int[] values = new int[n]; -for (int i = 0; i < n; i++) { - values[i] = in.nextInt(); -} -int cnt = 0; -int totalValue = 0; -for (int s = 0, e = c - 1; e < n; s++, e++) { - if (s == 0) { - for (int j = 0; j < c; j++) totalValue += values[j]; - } else { - totalValue = totalValue - values[s - 1] + values[e]; - } - if (totalValue <= t) cnt++; -} -System.out.println(cnt); -``` - -# 22. 百度-裁减网格纸 - -```java -int n = in.nextInt(); -int minX, minY, maxX, maxY; -minX = minY = Integer.MAX_VALUE; -maxX = maxY = Integer.MIN_VALUE; -for (int i = 0; i < n; i++) { - int x = in.nextInt(); - int y = in.nextInt(); - minX = Math.min(minX, x); - minY = Math.min(minY, y); - maxX = Math.max(maxX, x); - maxY = Math.max(maxY, y); -} -System.out.println((int) Math.pow(Math.max(maxX - minX, maxY - minY), 2)); -``` - -# 23. 百度-钓鱼比赛 - -P ( 至少钓一条鱼 ) = 1 - P ( 一条也钓不到 ) - -坑:读取概率矩阵的时候,需要一行一行进行读取,而不能直接用 in.nextDouble()。 - -```java -public static void main(String[] args) { - Scanner in = new Scanner(System.in); - while (in.hasNext()) { - int n = in.nextInt(); - int m = in.nextInt(); - int x = in.nextInt(); - int y = in.nextInt(); - int t = in.nextInt(); - in.nextLine(); // 坑 - double pcc = 0.0; - double sum = 0.0; - for (int i = 1; i <= n; i++) { - String[] token = in.nextLine().split(" "); // 坑 - for (int j = 1; j <= m; j++) { - double p = Double.parseDouble(token[j - 1]); - // double p = in.nextDouble(); - sum += p; - if (i == x && j == y) { - pcc = p; - } - } - } - double pss = sum / (n * m); - pcc = computePOfIRT(pcc, t); - pss = computePOfIRT(pss, t); - System.out.println(pcc > pss ? "cc" : pss > pcc ? "ss" : "equal"); - System.out.printf("%.2f\n", Math.max(pcc, pss)); - } -} - -// compute probability of independent repeated trials -private static double computePOfIRT(double p, int t) { - return 1 - Math.pow((1 - p), t); -} -``` - -# 24. 百度-蘑菇阵 - -这题用回溯会超时,需要用 DP。 - -dp[i][j] 表示到达 (i,j) 位置不会触碰蘑菇的概率。对于 N\*M 矩阵,如果 i == N || j == M,那么 (i,j) 只能有一个移动方向;其它情况下能有两个移动方向。 - -考虑以下矩阵,其中第 3 行和第 3 列只能往一个方向移动,而其它位置可以有两个方向移动。 - - -```java -int N = in.nextInt(); -int M = in.nextInt(); -int K = in.nextInt(); -boolean[][] mushroom = new boolean[N][M]; -while (K-- > 0) { - int x = in.nextInt(); - int y = in.nextInt(); - mushroom[x - 1][y - 1] = true; -} -double[][] dp = new double[N][M]; -dp[0][0] = 1; -for (int i = 0; i < N; i++) { - for (int j = 0; j < M; j++) { - if (mushroom[i][j]) dp[i][j] = 0; - else { - double cur = dp[i][j]; - if (i == N - 1 && j == M - 1) break; - if (i == N - 1) dp[i][j + 1] += cur; - else if (j == M - 1) dp[i + 1][j] += cur; - else { - dp[i][j + 1] += cur / 2; - dp[i + 1][j] += cur / 2; - } - } - } -} -System.out.printf("%.2f\n", dp[N - 1][M - 1]); -```