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

卖大米 2020-8-2 738


上岸算法

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

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

No.1 统计好三元组

★解题思路

简单地枚举即可, 三层循环.

代码展示


class Solution {
   public int countGoodTriplets(int[] arr, int a, int b, int c) {
       int n = arr.length;
       int res = 0;
       for (int i = 0; i < n; i++) {
           for (int j = i + 1; j < n; j++) {
               for (int k = j + 1; k < n; k++) {
                   if (isGood(arr, i, j, a) && isGood(arr, j, k, b) && isGood(arr, i, k, c)) {
                       res++;
                   }
               }
           }
       }
       return res;
   }

   boolean isGood(int[] arr, int a, int b, int c) {
       return Math.abs(arr[a] - arr[b]) <= c;
   }
}

No.2 找出数组游戏的赢家

解题思路

需要用单调栈求出每个元素后第一个比自己大的元素的位置 nextLarger 最终胜利的元素就是 nextLarger 与自己的距离超过 k 的第一个元素.

代码展示


class Solution {
   public int getWinner(int[] arr, int k) {
       // 单调栈
       int[] nextLarger = new int[arr.length];
       Stack<Integer> stack = new Stack<>();
       stack.push(0);
       for (int i = 1; i < arr.length; ) {
           if (!stack.isEmpty() && arr[i] > arr[stack.peek()]) {
               nextLarger[stack.pop()] = i;
           } else {
               stack.push(i++);
           }
       }
       while (!stack.isEmpty()) {
           nextLarger[stack.pop()] = arr.length;
       }

       for (int i = 0; i < arr.length; i++) {
           int win = i == 0 ? 0 : 1; // 若 i 不是第一个, 那么会赢一个前面的元素
           win += nextLarger[i] - i - 1; // 然后会连续赢到 nextLarger
           if (win >= k) return arr[i];
       }

       // 没有 win >= k 的, 即 k 过大 (大于数组长度), 此时直接返回数组最大值
       return Collections.max(Arrays.stream(arr).boxed().collect(Collectors.toList()));
   }
}

No.3 排布二进制网格的最少交换次数

★解题思路

模拟交换即可.

由于要主对角线上全部是 0, 所以行数越靠前, 要求越苛刻 —— 一行中 0 的数量越多.

所以我们从前面的行开始看, 只要不满足条件, 就在后面找到一行换上来.

代码展示


class Solution {
   public int minSwaps(int[][] grid) {
       int n = grid.length;
       int m = grid[0].length;

       // last1[i] 表示第 i 行的最后一个 1 的位置
       int[] last1 = new int[n];
       Arrays.fill(last1, -1);
       for (int i = 0; i < n; i++) {
           for (int j = 0; j < m; j++) {
               if (grid[i][j] == 1) last1[i] = j;
           }
       }

       int res = 0;
       for (int i = 0; i < n; i++) {
           // last1[i] <= i 说明这一行满足题目条件
           if (last1[i] <= i) continue;
           // 不满足则在后面找到满足条件的一行
           int pos = -1;
           for (int j = i + 1; j < n; j++) {
               if (last1[j] <= i) {
                   pos = j;
                   break;
               }
           }
           if (pos < 0) return -1;
           // 交换
           res += pos - i;
           int[] gBak = grid[pos];
           int lBak = last1[pos];
           for (int j = pos; j > i; j--) {
               grid[j] = grid[j - 1];
               last1[j] = last1[j - 1];
           }
           grid[i] = gBak;
           last1[i] = lBak;
       }
       return res;
   }
}

No.4 最大得分

★解题思路

贪心法.

找出共同的元素, 两个数组中共同的元素将两个数组分成若干段, 取比较大的那一段即可.

代码展示


class Common {
   public int pos1;
   public int pos2;

   public Common(int pos1, int pos2) {
       this.pos1 = pos1;
       this.pos2 = pos2;
   }
}

class Solution {
   public int maxSum(int[] nums1, int[] nums2) {
       int n = nums1.length;
       int m = nums2.length;

       // 前缀和, 稍后求区间和所用
       long[] presum1 = new long[n];
       long[] presum2 = new long[m];
       presum1[0] = nums1[0];
       for (int i = 1; i < n; i++) {
           presum1[i] = presum1[i - 1] + nums1[i];
       }
       presum2[0] = nums2[0];
       for (int i = 1; i < m; i++) {
           presum2[i] = presum2[i - 1] + nums2[i];
       }

       // 求出二者相同元素的位置
       List<Common> commons = new ArrayList<>();
       commons.add(new Common(-1, -1)); // 边界
       for (int i = 0, j = 0; i < n && j < m; ) {
           if (nums1[i] == nums2[j]) {
               commons.add(new Common(i, j));
               i++;
               j++;
           } else if (nums1[i] < nums2[j]) i++;
           else j++;
       }
       commons.add(new Common(n, m)); // 边界

       // 两个相邻的相同元素切割出一段, 取较大的那一段
       long res = 0;
       long MOD = 1000000007;
       for (int i = 1; i < commons.size(); i++) {
           Common last = commons.get(i - 1);
           Common curr = commons.get(i);
           long sum1 = getSum(last.pos1, curr.pos1, presum1);
           long sum2 = getSum(last.pos2, curr.pos2, presum2);
           res = (res + (Math.max(sum1, sum2) % MOD)) % MOD;
       }
       return (int) res;
   }

   private long getSum(int l, int r, long[] presum) {
       long lsum = 0, rsum = presum[presum.length - 1];
       if (l >= 0) lsum = presum[l];
       if (r < presum.length) rsum = presum[r];
       return rsum - lsum;
   }
}

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

上岸科技,一家位于西雅图致力于帮助北美小伙伴们上岸的团体。

团队主要由一群怀揣情怀于美国高校毕业的一线IT公司工程师构成。我们坚持采用小班课形式,并结合大量”面试式“和”白板“的教学和交流形式,最终帮助大家提升求职成功概率同时大大减少刷题的痛苦。

正如我们的信仰:我们教的是如何上岸而不仅是算法。

最新回复 (0)
返回