LeetCode Weekly Contest 187解题报告

卖大米 2020-5-3 601


No. 1旅行终点站

★解题思路

题目给定了若干条有向边, 最终没有出度的点就是终点站.

既然题目保证有解, 那么我们就直接查找那个没有做过出发站的站点即可.

代码展示


class Solution { 
   public String destCity(List<List<String>> paths) { 
       Set<String> set = new HashSet<>(); 
       for (var path : paths) { 
           set.add(path.get(0));  // 将做过出发站的站点加入集合 
       } 
       for (var path : paths) { 
           if (!set.contains(path.get(1))) { 
               return path.get(1);  // 没有做过出发站, 直接返回 
           } 
       } 
       return "";  // 题目保证有解, 不会执行到这一步 (但是不加这一句会 CE) 
   } 
}

No.2 是否所有 1 都至少相隔 k 个元素

★解题思路

记录上一次 1 出现的位置, 遍历一次即可.

代码展示


class Solution { 
   public boolean kLengthApart(int[] nums, int k) { 
       int last = - k - 1;  // 初始值设置为 - k - 1, 以防 nums[0] 是 1 的时候返回 false 
       for (int i = 0; i < nums.length; i++) { 
           if (nums[i] == 1) { 
               if (i - last <= k) { 
                   return false; 
               } 
               last = i; 
           } 
       } 
       return true; 
   } 
}

No.3 绝对差不超过限制的最长连续子数组

★解题思路

该题目需要用双指针 + 单调队列. 双指针用于维护当前的最大合法区间, 单调队列用于区间移动的时候能够快速找到下一个最大值和最小值.

代码展示


class Solution { 
   public int longestSubarray(int[] nums, int limit) { 
       if (limit < 0) { 
           return 0; 
       } 
       int res = 0; 
       // maxQueue 是当前区间 [l, r) 中的元素的单调下降队列, 因此队首就是最大值 
       // minQueue 是当前区间 [l, r) 中的元素的单调上升队列, 因此队首就是最小值 
       // 单调队列的队首是最大/小值, 第二个则是次大/小值, 第三个则是第三大/小值... 
       LinkedList<Integer> maxQueue = new LinkedList<>(); 
       LinkedList<Integer> minQueue = new LinkedList<>(); 
       for (int l = 0, r = 0; l < nums.length; l++) { 
           // 对于每一个左端点 l, 找到最大的 r 
           while (r < nums.length) { 
               int newMax = maxQueue.size() > 0 ? Math.max(nums[maxQueue.getFirst()], nums[r]) : nums[r]; 
               int newMin = minQueue.size() > 0 ? Math.min(nums[minQueue.getFirst()], nums[r]) : nums[r]; 
               // 若新加一个元素会导致绝对差超过限度, 则终止 
               if (maxQueue.size() > 0 && minQueue.size() > 0 && newMax - newMin > limit) { 
                   break; 
               } 
               // 新加元素前要维护单调队列的单调性 
               while (maxQueue.size() > 0 && nums[maxQueue.getLast()] < nums[r]) { 
                   maxQueue.removeLast(); 
               } 
               while (minQueue.size() > 0 && nums[minQueue.getLast()] > nums[r]) { 
                   minQueue.removeLast(); 
               } 
               maxQueue.addLast(r); 
               minQueue.addLast(r); 
               r++; 
           } 
           res = Math.max(res, r - l); 
           // 检查是否需要删除队首 
           if (maxQueue.size() > 0 && maxQueue.getFirst() == l) { 
               maxQueue.removeFirst(); 
           } 
           if (minQueue.size() > 0 && minQueue.getFirst() == l) { 
               minQueue.removeFirst(); 
           } 
       } 
       return res; 
   } 
}

No.4 有序矩阵中的第 k 个最小数组和

★解题思路

由于数据范围不大, 所以使用优先队列即可通过.

使用优先队列来保存取数情况 (每一行取第几个), 每一种取数情况的下一步就是把某一行的位置向后移动一个, 即有 n 个后继, 而优先队列的优先级就是取数情况所取出来的元素和.

最开始入队的是最小的取数情况, 即每一行都取第一个数. 每出队一个都将它的 n 个后继加入优先队列. 而第 k 个出队的就是答案.

这个过程还需要用 Set 来判断一种取数情况是否已经入队过.

代码展示


// 取数情况 (即一个数组, 记录每一行取数的下标) 
class Arr { 
   public static int len = 0; 
   public int[] arr; 
   public Arr() { 
       arr = new int[len]; 
   } 
   public Arr(Arr a) { 
       arr = Arrays.copyOf(a.arr, len); 
   } 

   @Override 
   public boolean equals(Object o) { 
       if (this == o) return true; 
       if (o == null || getClass() != o.getClass()) return false; 
       Arr arr1 = (Arr) o; 
       return Arrays.equals(arr, arr1.arr); 
   } 

   @Override 
   public int hashCode() { 
       return Arrays.hashCode(arr); 
   } 

   public int getSum(int[][] mat) { 
       int res = 0; 
       for (int i = 0; i < mat.length; i++) { 
           res += mat[i][arr[i]]; 
       } 
       return res; 
   } 
} 

class Solution { 
   public int kthSmallest(int[][] mat, int k) { 
       int n = mat.length, m = mat[0].length; 
       Arr.len = n; 
       Set<Arr> set = new HashSet<>(); 
       PriorityQueue<Arr> heap = new PriorityQueue<>(Comparator.comparingInt(a -> a.getSum(mat))); 
       Arr start = new Arr(); 
       heap.add(start); 
       set.add(start); 
       for (int i = 1; i < k; i++) { 
           Arr cur = heap.poll(); 
           for (int j = 0; j < n; j++) { 
               if (cur.arr[j] + 1 == m) continue; 
               Arr nxt = new Arr(cur); 
               nxt.arr[j]++; 
               if (!set.contains(nxt)) { 
                   heap.add(nxt); 
                   set.add(nxt); 
               } 
           } 
       } 
       return heap.peek().getSum(mat); 
   } 
}

最新回复 (0)
返回