牛客网试卷 括号匹配 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 import java.util.*; public class Solution { public boolean IsValidExp (String s) { Deque<Character> stack = new ArrayDeque <>(); Map<Character, Character> map = new HashMap <Character, Character>(); char [] chars = s.toCharArray(); for (int i=0 ; i<chars.length; i++) { if (chars[i] == '{' ) { stack.offerLast('}' ); } else if (chars[i] == '[' ) { stack.offerLast(']' ); } else if (chars[i] == '(' ) { stack.offerLast(')' ); } else if (!stack.isEmpty() && stack.peekLast().equals(chars[i])) { stack.pollLast(); } else { return false ; } } return stack.isEmpty(); } }
算24 Java 回溯, 经典面试题
给出4个1-10的数字,通过加减乘除,得到数字为24就算胜利。
福尔摩斯编码解码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 import java.util.*;public class Main { public static void main (String[] args) { Scanner scanner = new Scanner (System.in); String str = scanner.nextLine(); char [] chars = str.toCharArray(); int n = chars.length; if (n == 0 ) { System.out.println(0 ); return ;} long [] dp = new long [n]; dp[0 ] = 1 ; for (int i=1 ; i<n; i++) { dp[i] = dp[i-1 ]; if (chars[i-1 ] == '1' ) { if (i == 1 ) { dp[i] += 1 ; } else { dp[i] += dp[i-2 ]; } } if (i >= 2 && chars[i-2 ] == '1' ) { if (i == 2 ) { dp[i] += 1 ; } else { dp[i] += dp[i-3 ]; } } } System.out.println(dp[n-1 ]); } }
最短路径问题
1 Floyd 注意这一题k在最外面
使用邻接矩阵,Floyd 最短路径的子路径仍然是最短路径 dp[k][i][j] 为经过前k的节点,从i到j所能得到的最短路径 dp[k][i][j] = min(dp[k-1][i][k], dp[k-1][i][k], dp[k-1][k][j]) 状态dp[k][i][j]由dp[k-1][i][j](不经过k),dp[k-1][i,k]+dp[k-1][k][j](经过k)转移过来, 很容易可以看出,dp[k]的状态完全由dp[k-1]转移过来,只要我们把k放倒最外层循环中,就能保证无后效性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import java.util.*;public class Flody { public static void main (String[] args) { Scanner scanner = new Scanner (System.in); int N = scanner.nextInt(), K = scanner.nextInt(), M = scanner.nextInt(); long [][] g = new long [N+1 ][N+1 ]; for (int i = 0 ; i <= N; i++) { for (int j = 0 ; j <= N; j++) { g[i][j] = Integer.MAX_VALUE; } } for (int i = 0 ; i < M; i++) { int x = scanner.nextInt(), y = scanner.nextInt(), w = scanner.nextInt(); g[x][y] = w; } for (int i = 0 ; i <= N; i++) { g[i][i] = 0 ; } for (int k = 1 ; k <= N; k++) { for (int i = 1 ; i <= N; i++) { for (int j = 1 ; j <= N; j++) { if (g[i][k] != Integer.MAX_VALUE && g[k][j] != Integer.MAX_VALUE) { g[i][j] = Math.min(g[i][j], g[i][k] + g[k][j]); } } } } long ans = Integer.MIN_VALUE; for (int i = 1 ; i <= N; i++) { ans = Math.max(ans, g[K][i]); } System.out.println(ans == Integer.MAX_VALUE ? -1 : ans); } }
2 Dijikstra 最高效率的复习 【2022-08-20】美团秋招笔试五道编程题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import java.util.*;public class HighestFuXi { public static void main (String[] args) { Scanner scanner = new Scanner (System.in); int n = scanner.nextInt(), m = scanner.nextInt(); scanner.nextLine(); int [][] scores = new int [2 ][n]; scores[0 ] = Arrays.stream(scanner.nextLine().split(" " )).mapToInt(Integer::valueOf).toArray(); scores[1 ] = Arrays.stream(scanner.nextLine().split(" " )).mapToInt(Integer::valueOf).toArray(); double ans = 0.0 ; Queue<Double> queue = new PriorityQueue <>((a, b) -> { if (a.equals(b)) { return 0 ;} else if (b > a) { return 1 ;} return -1 ; }); for (int i = 0 ; i < n; i++) { ans += scores[0 ][i] * 1.0 / 100 * scores[1 ][i]; queue.offer((1 - scores[0 ][i] * 1.0 / 100 ) * scores[1 ][i]); } for (int i = 0 ; i < m; i++) { ans += queue.poll(); } System.out.println(ans); } }
拟合,两个数列变相同 下面有一个 拼多多的 【字符变换】的,但是那个题目对应的做法更简单一点。
两个数列,可以去掉其中一个,步数abs(a[i]),也可以一个变成另外一个,步数abs(a[i] - b[i]),问最少步数两者相同。
思路 跟最长公共子序列差不多,dp[i][j],先考虑边界,在考虑递推式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 import java.util.*;public class NiHe { public static void main (String[] args) { Scanner scanner = new Scanner (System.in); int n = scanner.nextInt(), m = scanner.nextInt(); scanner.nextLine(); int [] a = Arrays.stream(scanner.nextLine().split(" " )).mapToInt(Integer::valueOf).toArray(); int [] b = Arrays.stream(scanner.nextLine().split(" " )).mapToInt(Integer::valueOf).toArray(); int [][] dp = new int [n+1 ][m+1 ]; for (int i = 1 ; i < n + 1 ; i++) { dp[i][0 ] = dp[i-1 ][0 ] + Math.abs(a[i-1 ]); } for (int i = 1 ; i < m + 1 ; i++) { dp[0 ][i] = dp[0 ][i-1 ] + Math.abs(b[i-1 ]); } for (int i = 1 ; i < n + 1 ; i++) { for (int j = 1 ; j < m + 1 ; j++) { if (a[i-1 ] == b[i-1 ]) { dp[i][j] = dp[i-1 ][j-1 ]; } else { dp[i][j] = Math.min(dp[i-1 ][j-1 ] + Math.abs(a[i-1 ] - b[j-1 ]), Math.min(dp[i-1 ][j] + Math.abs(a[i-1 ]), dp[i][j-1 ] + Math.abs(b[j-1 ]))); } } } System.out.println(dp[n][m]); } }
回顾,最长公共子序列 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Solution { public int longestCommonSubsequence (String text1, String text2) { int n = text1.length(), m = text2.length(); char [] a = text1.toCharArray(); char [] b = text2.toCharArray(); int [][] dp = new int [n+1 ][m+1 ]; for (int i=1 ; i<=n; i++) { for (int j=1 ; j<=m; j++) { if (a[i-1 ] == b[j-1 ]) { dp[i][j] = dp[i-1 ][j-1 ] + 1 ; } else { dp[i][j] = Math.max(dp[i-1 ][j], dp[i][j-1 ]); } } } return dp[n][m]; } }
修补 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 import java.util.*;public class XiuBu { public static void main (String[] args) { Scanner scanner = new Scanner (System.in); int n = scanner.nextInt(), m = scanner.nextInt(); scanner.nextLine(); int [] a = Arrays.stream(scanner.nextLine().split(" " )).mapToInt(Integer::valueOf).toArray(); int [] b = Arrays.stream(scanner.nextLine().split(" " )).distinct(). sorted((x, y) -> Integer.parseInt(x) - Integer.parseInt(y)).mapToInt(Integer::valueOf).toArray(); long ans = 0 ; for (int i = 0 ; i < n; i++) { int left = 0 , right = m; while (left <= right) { int mid = (left + (right - left >> 1 )); if (b[mid] == a[i]) { left = right = mid; break ; } else if (b[mid] > a[i]) { right = mid - 1 ; } else { left = mid + 1 ; } } ans += b[left]; } System.out.println(ans); } }
美团2021_10 公司食堂 注意: 1 每次取最左边的餐桌,所以用了两个小根队。
2 卡输出,先用StringBuilder将所有输出缓存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 import java.util.*;public class Main { public static void main (String[] args) { Scanner scanner = new Scanner (System.in); int T = Integer.parseInt(scanner.nextLine()); StringBuilder ans = new StringBuilder (); while (T-- != 0 ) { int N = Integer.parseInt(scanner.nextLine()); String desk = scanner.nextLine(); char [] deskChars = desk.toCharArray(); int paidui = Integer.parseInt(scanner.nextLine()); String sexes = scanner.nextLine(); Queue<Integer> zeroQueue = new PriorityQueue <>(); Queue<Integer> oneQueue = new PriorityQueue <>(); for (int i=1 ; i<=N; i++) { if (deskChars[i-1 ] == '1' ) { oneQueue.offer(i); } else if (deskChars[i-1 ] == '0' ) { zeroQueue.offer(i); } } for (Character c: sexes.toCharArray()) { int deskNum = 0 ; if (c == 'F' ) { if (!zeroQueue.isEmpty()) { deskNum = zeroQueue.poll(); oneQueue.offer(deskNum); } else { deskNum = oneQueue.poll(); } } else { if (!oneQueue.isEmpty()) { deskNum = oneQueue.poll(); } else { deskNum = zeroQueue.poll(); oneQueue.offer(deskNum); } } ans.append(deskNum).append("\n" ); } } System.out.println(ans); } }
最优二叉树 使用分治 + 记忆化搜索的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 import java.util.*;public class Main { static int [][][] dp; public static void main (String[] args) { Scanner scanner = new Scanner (System.in); int n = Integer.parseInt(scanner.nextLine()); int [] nums = Arrays.stream(scanner.nextLine().split(" " )).mapToInt(Integer::valueOf).toArray(); dp = new int [n][n][n]; for (int i=0 ; i<n; i++) { for (int j=0 ; j<n; j++) { for (int k=0 ; k<n; k++) { dp[i][j][k] = -1 ; } } } int ans = dfs(0 , n-1 , -1 , nums); System.out.println(ans); } public static int dfs (int left, int right, int root, int [] nums) { if (left > right) { return 0 ; } if (root >= 0 && dp[left][right][root] != -1 ) { return dp[left][right][root]; } int cost = Integer.MAX_VALUE; for (int index = left; index <= right; index++) { int leftCost = dfs(left, index-1 , index, nums); int rightCost = dfs(index+1 , right, index, nums); cost = Math.min(cost, leftCost + rightCost + nums[index] * (root == -1 ? 0 : nums[root])); } if (root > 0 ) { dp[left][right][root] = cost; } return cost; } }
拼多多 多多的求和计算 
如果,二维朴素计算,稍微大了点。
所以用map存取模的前缀和,然后可以用来求区间个数。注意最后本来就是0的情况。
还有Map也要用Long。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import java.util.*;public class Main { public static void main (String[] args) { Scanner scanner = new Scanner (System.in); int N = scanner.nextInt(), M = scanner.nextInt(); scanner.nextLine(); int [] nums = Arrays.stream(scanner.nextLine().split(" " )).mapToInt(Integer::valueOf).toArray(); Map<Long, Long> map = new HashMap <>(); long [] sums = new long [N + 1 ]; for (int i = 1 ; i <= N; i++) { sums[i] = (sums[i - 1 ] + (nums[i - 1 ] % M)) % M; map.put(sums[i], map.getOrDefault(sums[i], 0L ) + 1 ); } System.out.println(map.values().stream().map(n -> n * (n - 1 ) / 2 ).reduce(0L , Long::sum) + map.getOrDefault(0L , 0L )); } }
数组组合 定义为:每个数字的十进制表示中(0~9),每个数位各不相同 且各个数位之和等于N。 满足条件的数字可能很多,找到其中的最小值即可。
多多君还有很多研究课题,于是多多君找到了你–未来的计算机科学家寻求帮助。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 import java.util.Scanner; public class Main { public static void main (String[] args) { Scanner scanner = new Scanner (System.in); int N = scanner.nextInt(); if (N > 45 ){ System.out.println(-1 ); System.exit(0 ); } StringBuilder stringBuilder = new StringBuilder (); for (int i = 9 ; i > 0 ; i--) { if (N>=i){ N-=i; stringBuilder.insert(0 ,i); } } System.out.println(stringBuilder.toString()); } } import java.util.*;public class Main { static List<Integer> ans; public static void main (String[] args) { Scanner scanner = new Scanner (System.in); int sum = scanner.nextInt(); if (sum > 50 ) { System.out.println(-1 ); return ; } int [] nums = new int []{0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 }; for (int step = 1 ; step <= 10 ; step += 1 ) { dfsTrace(nums, 0 , step, new ArrayList <>(), sum); } if (ans == null ) { System.out.println(-1 ); return ; } int ansVal = 0 ; for (int num: ans) { ansVal = (ansVal * 10 ) + num; } System.out.println(ansVal); } public static void dfsTrace (int [] nums, int curIndex, int step, List<Integer> curNums, int sum) { if (step == curNums.size()) { if (curNums.stream().mapToInt(Integer::valueOf).sum() == sum) { ans = new ArrayList <>(curNums); } return ; } if (ans != null || curIndex >= nums.length) { return ; } curNums.add(nums[curIndex]); dfsTrace(nums, curIndex + 1 , step, curNums, sum); curNums.remove(curNums.size() - 1 ); dfsTrace(nums, curIndex + 1 , step, curNums, sum); } }
字符变换 注意和上面的美团的 【拟合,两个数列变相同】 这动态规划题目做比较。
多多君最近在研究字符串之间的变换,可以对字符串进行若干次变换操作:
交换任意两个相邻的字符,代价为0。
将任意一个字符a修改成字符b,代价为 |a - b|(绝对值)。
现在有两个长度相同的字符串X和Y,多多君想知道,如果要将X和Y变成两个一样的字符串,需要的最少的代价之和是多少。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import java.util.*;public class Main { public static void main (String[] args) { Scanner scanner = new Scanner (System.in); int n = Integer.parseInt(scanner.nextLine()); String a = scanner.nextLine(); String b = scanner.nextLine(); char [] aChars = a.toCharArray(); char [] bChars = b.toCharArray(); Arrays.sort(aChars); Arrays.sort(bChars); int ans = 0 ; for (int i = 0 ; i < aChars.length; i++) { ans += Math.abs(aChars[i] - bChars[i]); } System.out.println(ans); } }