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

卖大米 2020-7-5 669


上岸算法

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

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

No.1 判断能否形成等差数列

★解题思路

排序之后依次判断每两对相邻的差是否相等即可.

代码展示


class Solution { 
   public boolean canMakeArithmeticProgression(int[] arr) { 
       Arrays.sort(arr); 
       for (int i = 2; i < arr.length; i++) { 
           if (arr[i] - arr[i - 1] != arr[i - 1] - arr[i - 2]) { 
               return false; 
           } 
       } 
       return true; 
   } 
}

No.2 所有蚂蚁掉下来前的最后一刻

解题思路

两只蚂蚁相遇改变方向等价于两只蚂蚁穿过了对方.

代码展示


class Solution { 
   public int getLastMoment(int n, int[] left, int[] right) { 
       int res = 0; 
       for (int l : left) { 
           res = Math.max(l, res); 
       } 
       for (int r : right) { 
           res = Math.max(n - r, res); 
       } 
       return res; 
   } 
}

No.3 统计全1子矩形

★解题思路

见注释.

代码展示


class Solution { 
   public int numSubmat(int[][] mat) { 
       int n = mat.length, m = mat[0].length; 
       // 预处理, 计算前缀和. sum[i][j] 表示 (0, 0) 到 (i, j) 的子矩形的和  
       int[][] sum = new int[n][m]; 
       for (int i = 0; i < n; i++) { 
           sum[i][0] = mat[i][0] + (i == 0 ? 0 : sum[i - 1][0]); 
           for (int j = 1; j < m; j++) { 
               sum[i][j] = sum[i][j - 1] + mat[i][j]; 
               if (i == 0) { 
                   sum[i][j] = sum[i][j - 1] + mat[i][j]; 
               } else { 
                   sum[i][j] = sum[i][j - 1] + sum[i - 1][j] - sum[i - 1][j - 1] + mat[i][j]; 
               } 
           } 
       } 

       int res = 0; 
       // 依次统计以每个点 (i, j) 为左上角的全 1 子矩阵的数量 
       for (int i = 0; i < n; i++) { 
           for (int j = 0; j < m; j++) { 
               // 依次统计右下角在每一行 (k) 时有多少个子矩阵 
               for (int k = i; k < n; k++) { 
                   if (!checkAllOne(i, j, k, j, sum)) break; 
                   // 二分计算右下角在第 k 行时, 最大的全 1 矩阵 
                   int l = j, r = m - 1; 
                   while (l + 1 < r) { 
                       int mid = (l + r) / 2; 
                       if (checkAllOne(i, j, k, mid, sum)) { 
                           l = mid; 
                       } else { 
                           r = mid; 
                       } 
                   } 
                   if (checkAllOne(i, j, k, r, sum)) { 
                       res += r - j + 1; 
                   } else { 
                       res += l - j + 1; 
                   } 
               } 
           } 
       } 
       return res; 
   } 

   private boolean checkAllOne(int i, int j, int i2, int j2, int[][] sum) { 
       // 检查以 (i, j) 为左上角, (i2, j2) 为右下角的子矩阵是否全为 1 
       int size = (j2 - j + 1) * (i2 - i + 1); 
       int _all = sum[i2][j2]; 
       int _left = j == 0 ? 0 : sum[i2][j - 1]; 
       int _up = i == 0 ? 0 : sum[i - 1][j2]; 
       int _upLeft = i == 0 || j == 0 ? 0 : sum[i - 1][j - 1]; 
       int allSum = _all - _left - _up + _upLeft; 
       return allSum == size; 
   } 
}

No.4

最多K次交换相邻数位后得到的最小整数

解题思路

基本思路:

优先缩小高位

尝试缩小一个数即找它后面最小的能在 k 次交换之后移动到这个位置的数

需要使用数状数组辅助维护第 2 点

代码展示


class Solution { 
   private int[] _sum; // 树状数组 

   void add(int x, int v) { 
       while (x < _sum.length) { 
           _sum[x] += v; 
           x += x & (-x); 
       } 
   } 

   int sum(int x) { 
       int ret = 0; 
       while (x != 0) { 
           ret += _sum[x]; 
           x -= x & (-x); 
       } 
       return ret; 
   } 

   String minInteger(String num, int k) { 
       _sum = new int[num.length() + 1]; 
       StringBuilder res = new StringBuilder(); 
       Map<Character, LinkedList<Integer>> rawPos = new HashMap<>(); // rawPos[i] 表示字符 i 出现的位置序列 
       int[] next = new int[10]; // next[i] 表示 rawPos[i] 用到了哪一个 
       // 初始化计算 rawPos 
       for (char c = '0'; c <= '9'; c++) { 
           rawPos.put(c, new LinkedList<>()); 
       } 
       for (int i = 0; i < num.length(); i++) { 
           char c = num.charAt(i); 
           rawPos.get(c).add(i); 
       } 
       // 计算答案 
       for (int i = 0; i < num.length(); i++) { 
           // 尝试将字符 j 从后面一个一个地交换, 直到换到 i 位置 
           // (若 jChar 就是 num[i] 本身, 则不消耗交换次数) 
           for (int j = 0; j < 10; j++) { 
               char jChar = (char)(j + '0'); 
               if (next[j] == rawPos.get(jChar).size()) { // j 已经用完了, continue 
                   continue; 
               } 
               int p = rawPos.get(jChar).get(next[j]); 
               if (k >= p + sum(p + 1) - i) { // 加上整体偏移量 
                   k -= p + sum(p + 1) - i; 
                   next[j]++; 
                   res.append(jChar); 
                   // 使用数状数组维护整体偏移量 
                   add(1, 1);  
                   add(p + 1, -1); 
                   break; 
               } 
           } 
       } 
       return res.toString(); 
   } 
}

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

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

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

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

最新回复 (0)
返回