上岸 I LeetCode Weekly Contest 191解题报告 算法 刷题解法

卖大米 2020-5-31 660


上岸算法

死磕100%上岸率的精品小班课

关注我们,第一时间获得大厂面试真题讲解

No.1 数组中两元素的最大乘积

★解题思路

一次循环即可统计出第一大和第二大的元素.

代码展示

class Solution {   public int maxProduct(int[] nums) {       int first = Math.max(nums[0], nums[1]);       int second = Math.min(nums[0], nums[1]);       for (int i = 2; i < nums.length; i++) {           if (nums[i] > first) {               second = first;               first = nums[i];           } else {               second = Math.max(second, nums[i]);           }       }       return (first - 1) * (second - 1);   } }

No.2 切割后面积最大的蛋糕

★解题思路

找出切割后的最大子矩形的长和宽即可.

代码展示

class Solution {   public int maxArea(int h, int w, int[] horizontalCuts, int[] verticalCuts) {       long maxw = maxLength(h, horizontalCuts);       long maxh = maxLength(w, verticalCuts);       return (int) (maxw * maxh % 1000000007);   }   // 返回边长为 n, 切点为 cuts 的情况, 切割之后的最大边长   private long maxLength(int n, int[] cuts) {       Arrays.sort(cuts);       long res = Math.max(cuts[0], n - cuts[cuts.length - 1]);       for (int i = 1; i < cuts.length; i++) {           res = Math.max(res, cuts[i] - cuts[i - 1]);       }       return res;   } }

No.3 重新规划路线

★解题思路

原本所有的有向边 (a, b) 的含义可以理解为从 a 走到 b 的耗费是 0, 而从 b 走到 a 的耗费为 1. 那么从城市 x 走到城市 0, 需要改变的道路方向的数量就是这条路径的累积耗费.

但是依次从每一个点走向 0 并不容易实现, 我们改为求解对称的问题: 从 0 走到每一个点 —— 对应地将每条边也反向.

代码展示

class Solution {   public int minReorder(int n, int[][] connections) {       Map<Integer,List<Integer>> neighbors = new HashMap<>();       // 构造邻接表, 便于 dfs       // neighbors[i] 表示 i 可以到达的点以及距离       for (var conn : connections) {           int a = conn[0], b = conn[1];           // 因为求解对称问题, 所以原图 a -> b 的有向边对应           // a->b (1) 和 b->a (0)           neighbors.computeIfAbsent(a, k -> new ArrayList<>());           neighbors.computeIfAbsent(b, k -> new ArrayList<>());           neighbors.get(a).add(b);           neighbors.get(a).add(1);           neighbors.get(b).add(a);           neighbors.get(b).add(0);       }       return dfs(0, -1, neighbors);   }   private int dfs(int cur, int pre, Map<Integer, List<Integer>> neighbors) {       int res = 0;       int n = neighbors.get(cur).size();       for (int i = 0; i < n; i += 2) {           int next = neighbors.get(cur).get(i);           int len = neighbors.get(cur).get(i + 1);           if (next != pre) {               res += dfs(next, cur, neighbors) + len;           }       }       return res;   } }

No.4 两个盒子中球的颜色数相同的概率

★ 解题思路

最终答案 = 使得两个盒子中球的颜色数相同的方案数量 / 总方案数量

其中总方案数量即组合数 "从 2n 个球中拿出 n 个球的方案数".

使得两个盒子中球的颜色数相同的方案数量可以通过枚举求解.

代码展示

class Solution {   private int sum;   public double getProbability(int[] balls) {       sum = 0;       for (int ball : balls) {           sum += ball;       }       return 1.0 * dfs(0, 0, 0, 0, 0, 1, balls) / C(sum / 2, sum);   }   // i 表示枚举到哪种球了   // j1, j2 表示两个盒子中球的数量, 最终两个盒子中球的数量都是 sum / 2   // k1, k2 表示两个盒子中颜色的数量, 最终 k1 == k2   // cnt 表示走到当前这一种状态的方案数量   private long dfs(int i, int j1, int j2, int k1, int k2, long cnt, int[] balls) {       if (j1 > sum / 2 || j2 > sum / 2) {           return 0;       }       if (i == balls.length) {           return k1 == k2 ? cnt : 0;       }       long res = 0;       // 考虑 balls[i] 有多少个球放进了盒子 1       // 把 j 个球放进盒子 1 的方案数为 C(j, balls[i])       // 乘法原理       res += dfs(i + 1, j1, j2 + balls[i], k1, k2 + 1, cnt * 1, balls);       res += dfs(i + 1, j1 + balls[i], j2, k1 + 1, k2, cnt * 1, balls);       for (int j = 1; j < balls[i]; j++) {           res += dfs(i + 1, j1 + j, j2 + balls[i] - j, k1 + 1, k2 + 1,                   cnt * C(j, balls[i]), balls);       }       return res;   }   private long[][] memC = new long[25][50];   private long C(int a, int b) {       if (a == b || a == 0) {           return 1;       }       if (memC[a][b] > 0) {           return memC[a][b];       }       memC[a][b] = C(a - 1, b - 1) + C(a, b - 1);       return memC[a][b];   } }

杭州上岸算法网络科技有限公司

上岸科技是一家【死磕100%上岸率】的小公司。

核心团队和老师均来自于行业内知名公司,我们坚持采用小班课形式,并结合大量”面试式“和”白板“的教学和交流形式,最终做到摆渡【每个人】成功上岸的承诺。

我们对每个人负责,上岸,一个都不能少!

最后于 2020-6-1 被maomoke编辑 ,原因:
最新回复 (0)
返回