算法分类2 双指针 还有检查链表的环 滑动窗口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Solution { public int lengthOfLongestSubstring (String s) { int ans = 0 ; Set<Character> set = new HashSet <Character>(); int left = 0 ; for (int right=0 ; right<s.length(); right++) { while (left <= right && set.contains(s.charAt(right))) { set.remove(s.charAt(left)); left++; } set.add(s.charAt(right)); ans = Math.max(right - left + 1 , ans); } return ans; } }
11. 盛最多水的容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution { public int maxArea (int [] height) { int left = 0 , right = height.length-1 ; int ans = 0 ; while (left < right) { ans = Math.max(Math.min(height[left], height[right]) * (right - left), ans); if (height[left] < height[right]) { left++; } else { right--; } } return 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 class Solution { public List<List<Integer>> threeSum (int [] nums) { Arrays.sort(nums); List<List<Integer>> list = new ArrayList <>(); for (int i=0 ; i<nums.length; i++) { if (i > 0 && nums[i] == nums[i-1 ]) { continue ; } int j = i+1 , k = nums.length - 1 ; while (j < k) { while (j > i+1 && j < k && nums[j] == nums[j-1 ]) { j++; } if (j >= k) { break ; } int sum = nums[i] + nums[j] + nums[k]; if (sum == 0 ) { list.add(Arrays.asList(nums[i], nums[j], nums[k])); j++; } else if (sum < 0 ) { j++; } else { k--; } } } return list; } }
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 class Solution { public int threeSumClosest (int [] nums, int target) { Arrays.sort(nums); int ans = nums[0 ] + nums[1 ] + nums[2 ]; for (int i=0 ; i<nums.length; i++) { int j = i + 1 , k = nums.length - 1 ; while (j < k) { int sum = nums[i] + nums[j] + nums[k]; ans = Math.abs(target - ans) > Math.abs(target - sum) ? sum : ans; if (sum == target) { return ans; } else if (sum < target) { j++; } else { k--; } } } return ans; } }
二分 主要的特点是
升序排列,不论是一个数组还是两个数组。
时间复杂度O(log(m)), O(log(m+n))之类的
二分需要注意很多等号,左右边,等等的细节
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Solution { public int findDuplicate (int [] nums) { Arrays.sort(nums); int left = 0 , right = nums.length - 1 ; while (left <= right) { int mid = left + (right - left >> 1 ); if (nums[mid] == nums[mid+1 ]) { return nums[mid]; } else if (nums[mid] < mid+1 ) { right = mid - 1 ; } else { left = mid + 1 ; } } return -1 ; } }
由于中位数是(n+m)/2或者(n+m)/2和(n+m)/2+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 class Solution { public int search (int [] nums, int target) { int left = 0 , right = nums.length - 1 ; if (nums[0 ] == target) { return 0 ; } while (left <= right) { int mid = left + ((right - left) >> 1 ); if (nums[mid] == target) { return mid; } else { if (nums[0 ] > nums[mid]) { if (nums[mid] < target && target <= nums[nums.length - 1 ]) { left = mid + 1 ; } else { right = mid - 1 ; } } else { if (nums[0 ] <= target && target < nums[mid]) { right = mid - 1 ; } else { left = mid + 1 ; } } } } return -1 ; } }
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 class Solution { public boolean search (int [] nums, int target) { int left = 0 , right = nums.length - 1 ; if (nums[0 ] == target) { return true ; } while (left <= right) { int mid = left + ((right - left) >> 1 ); if (nums[mid] == target) { return true ; } if (nums[left] == nums[mid] && nums[mid] == nums[right]) { left++; right--; } else if (nums[left] > nums[mid]) { if (nums[mid] < target && target <= nums[nums.length - 1 ]) { left = mid + 1 ; } else { right = mid - 1 ; } } else { if (nums[left] <= target && target < nums[mid]) { right = mid - 1 ; } else { left = mid + 1 ; } } } return false ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public int findMin (int [] nums) { int left = 0 , right = nums.length - 1 , len = nums.length; while (left <= right) { int mid = left + ((right - left) >> 1 ); if (nums[mid] <= nums[len - 1 ]) { right = mid - 1 ; } else { left = mid + 1 ; } } return nums[left]; } }
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 class Solution { public int findMin (int [] nums) { int left = 0 , right = nums.length - 1 , len = nums.length - 1 ; while (left <= right) { int mid = left + ((right - left) >> 1 ); if (nums[mid] == nums[len]) { right -= 1 ; len = right; } else if (nums[mid] > nums[len]) { left = mid + 1 ; } else { right = mid - 1 ; len = mid; } } return nums[left]; } }
和target一样的,最左边的下标和最右边的下标 请非常关注里面的细节
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 class Solution { public int [] searchRange(int [] nums, int target) { if (nums.length == 0 ) { return new int []{-1 , -1 }; } int [] ans = new int [2 ]; int left = 0 , right = nums.length - 1 ; while (left <= right) { int mid = left + ((right - left) >> 1 ); if (nums[mid] >= target) { right = mid - 1 ; } else { left = mid + 1 ; } } if (left == nums.length || nums[left] != target) { return new int []{-1 , -1 }; } ans[0 ] = left; left = 0 ; right = nums.length - 1 ; while (left <= right) { int mid = left + ((right - left) >> 1 ); if (nums[mid] <= target) { left = mid + 1 ; } else { right = mid - 1 ; } } if (right == -1 || nums[right] != target) { return new int []{-1 , -1 }; } ans[1 ] = right; return ans; } }
找第一个比target大于等于的 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); } }
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 class Solution { public int minAbsoluteSumDiff (int [] nums1, int [] nums2) { long sum = 0 ; long duoJianQuMax = 0 ; int [] sortedNums1 = nums1.clone(); Arrays.sort(sortedNums1); for (int i=0 ; i< sortedNums1.length; i++) { int a = nums1[i], b = nums2[i]; if (a == b) { continue ; } int x = Math.abs(a - b); sum += x; int left = 0 , right = sortedNums1.length - 1 ; while (left <= right) { int mid = (left + ((right - left) >> 1 )); if (sortedNums1[mid] <= b) { left = mid + 1 ; } else { right = mid - 1 ; } } int c = Integer.MAX_VALUE; if (left != sortedNums1.length) { c = Math.abs(b - sortedNums1[left]); } if (right != -1 ) { c = Math.min(Math.abs(b - sortedNums1[right]), c); } if (c < x) { duoJianQuMax = Math.max(duoJianQuMax, x - c); } } return (int )((sum - duoJianQuMax) % (1e9 +7 )); } }
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 class Solution { public int searchInsert (int [] nums, int target) { int left = 0 , right = nums.length-1 ; while (left <= right) { int mid = left + ((right - left) >> 1 ); if (nums[mid] == target) { left = mid; break ; } else if (nums[mid] > target) { right = mid - 1 ; } else { left = mid + 1 ; } } return left; } } class Solution { public int searchInsert (int [] nums, int target) { int left = 0 , right = nums.length - 1 ; while (left <= right) { int mid = left + ((right - left) >> 1 ); if (nums[mid] == target) { return mid; } else if (nums[mid] > target) { right = mid - 1 ; } else { left = mid + 1 ; } } return left; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public boolean searchMatrix (int [][] matrix, int target) { int row = 0 , col = matrix[0 ].length - 1 ; while (true ) { if (matrix[row][col] == target) { return true ; } else if (matrix[row][col] > target) { col -= 1 ; if (col < 0 ) { break ; } } else { row += 1 ; if (row >= matrix.length) { break ; } } } return false ; }
这道题目不错的,二分,位运算找完全二叉树路径
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 class Solution { public int countNodes (TreeNode root) { if (root == null ) { return 0 ; } int height = getHeight(root, 0 ); int left = (int ) Math.pow(2 , height-1 ), right = (int ) Math.pow(2 , height) - 1 ; while (left <= right) { int mid = left + ((right - left) >> 1 ); TreeNode node = root; for (int i=height-2 ; i>=0 ; i--) { if (((mid >> i) & 1 ) == 1 ) { node = node.right; } else { node = node.left; } } if (node == null ) { right = mid - 1 ; } else { left = mid + 1 ; } } return right; } public int getHeight (TreeNode node, int height) { if (node == null ) { return height; } return Math.max(getHeight(node.left, height + 1 ), getHeight(node.right, height + 1 )); } }
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 class Solution { public int [] answerQueries(int [] nums, int [] queries) { Arrays.sort(nums); int [] sums = new int [nums.length + 1 ]; for (int i = 1 ; i <= nums.length; i++) { sums[i] = sums[i - 1 ] + nums[i - 1 ]; } int [] ans = new int [queries.length]; for (int i = 0 ; i < queries.length; i++) { int target = queries[i]; int left = 1 , right = sums.length - 1 ; while (left <= right) { int mid = left + ((right - left) >> 1 ); if (sums[mid] == target) { left = right = mid; break ; }else if (sums[mid] < target) { left = mid + 1 ; } else { right = mid - 1 ; } } ans[i] = right; } return ans; } }
滑动窗口 连续子数组
如果子数组的函数计算,是要小于(等于)某个东西 ,没有重复等等,那么可以使用经典滑动窗口 ,每一次移动一次right,然后left的移动看是否满足条件就可以。
而如果像LeetCode 395,子数组所有的字符出现次数大于 等于(不少于k次)。也就是说,一开始最小的数组是不满足的 ,就不像我上面的每次right移动一次,left看条件。
所以,但是好像也不能每次动left,然后把right移动到满足条件那样,因为不知道何时是头,一旦满足,但是后面还有满足的呢?
那么,可以尝试加一些限制条件,变成经典滑动窗口。比如:①395,加字符种类限制;②先把一些加上,然后变成0;③然后比如,题目说去除某个子数组之后,是否满足xxx,那么可以反过来看这个子数组自身的情况。④比如下面的209,将结果放在那个while数组里面,居然能解出来了
也可以看看宫水三叶说的,二段性质 ,两个指针,一个左移的时候往一个方向变,右移的时候往另一个方向变 ,应该就能用。那这样的话,我上面说的第二点,可能遇到二段性质的也能用?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public int minSubArrayLen (int target, int [] nums) { int left = 0 ; int sum = 0 , ans = Integer.MAX_VALUE; for (int right = 0 ; right < nums.length; right++) { sum += nums[right]; while (left <= right && sum >= target) { ans = Math.min(ans, right - left + 1 ); sum -= nums[left]; left += 1 ; } } return ans = = Integer.MAX_VALUE ? 0 : ans; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Solution { public int numSubarrayProductLessThanK (int [] nums, int k) { int mul = 1 , ans = 0 ; int n = nums.length, left = 0 ; for (int right=0 ; right<n; right++) { mul *= nums[right]; while (left <= right && mul >= k) { mul /= nums[left]; left++; } ans += right - left + 1 ; } return 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 class Solution { public int longestSubstring (String s, int k) { char [] chars = s.toCharArray(); int n = chars.length; int ans = 0 ; for (int p = 1 ; p <= 26 ; p++) { int left = 0 ; int zhonglei = 0 ; int kZhonglei = 0 ; int [] nums = new int [26 ]; for (int right = 0 ; right < n; right++) { int index = chars[right] - 'a' ; nums[index] += 1 ; if (nums[index] == 1 ) { zhonglei += 1 ; } if (nums[index] == k) { kZhonglei += 1 ; } while (left < right && zhonglei > p) { int tempIndex = chars[left] - 'a' ; nums[tempIndex] -= 1 ; if (nums[tempIndex] == 0 ) { zhonglei -= 1 ; } if (nums[tempIndex] == k - 1 ) { kZhonglei -= 1 ; } left += 1 ; } if (kZhonglei == zhonglei) { ans = Math.max(ans, right - left + 1 ); } } } return ans; } }
【宫水三叶】详解「朴素位运算」& 「哈希表位运算」,以完整的优化分析思路
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution { public int equalSubstring (String s, String t, int maxCost) { int n = Math.min(s.length(), t.length()), left = 0 ; int ans = 0 , cost = 0 ; for (int right = 0 ; right < n; right++) { cost += Math.abs(s.charAt(right) - t.charAt(right)); while (left <= right && cost > maxCost) { cost -= Math.abs(s.charAt(left) - t.charAt(left)); left++; } ans = Math.max(ans, right - left + 1 ); } return 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 class Solution { public int maxConsecutiveAnswers (String answerKey, int k) { int n = answerKey.length(); int left = 0 , changeNum = 0 , ans = 0 ; for (int right = 0 ; right < n; right++) { if (answerKey.charAt(right) == 'T' ) { changeNum++; } while (left <= right && changeNum > k) { if (answerKey.charAt(left) == 'T' ) { changeNum--; } left++; } ans = Math.max(ans, right - left + 1 ); } changeNum = 0 ; left = 0 ; for (int right = 0 ; right < n; right++) { if (answerKey.charAt(right) == 'F' ) { changeNum++; } while (left <= right && changeNum > k) { if (answerKey.charAt(left) == 'F' ) { changeNum--; } left++; } ans = Math.max(ans, right - left + 1 ); } return 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 class Solution { public int characterReplacement (String s, int k) { int ans = 0 ; for (int m = 0 ; m<26 ; m++) { int left = 0 ; int changeCount = 0 ; for (int right = 0 ; right < s.length(); right++) { if (s.charAt(right) != m + 'A' ) { changeCount++; } while (left <= right && changeCount > k) { if (s.charAt(left) != m + 'A' ) { changeCount--; } left++; } ans = Math.max(ans, right - left + 1 ); } } return 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 class Solution { public int maxSatisfied (int [] customers, int [] grumpy, int minutes) { int ans = 0 ; for (int i=0 ; i<customers.length; i++) { if (grumpy[i] == 0 ) { ans += customers[i]; customers[i] = 0 ; } } int sum = 0 , nextAns = 0 , left = 0 ; for (int right = 0 ; right < customers.length; right++) { sum += customers[right]; while (right - left > minutes-1 ) { sum -= customers[left]; left += 1 ; } nextAns = Math.max(sum, nextAns); } return ans + nextAns; } }
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 class Solution { public double [] medianSlidingWindow(int [] nums, int k) { Queue<Integer> left = new PriorityQueue <Integer>((x, y) -> (Integer.compare(x, y))); Queue<Integer> right = new PriorityQueue <Integer>((x, y) -> (Integer.compare(y, x))); for (int i=0 ; i<k; i++) { left.offer(nums[i]); } for (int i=0 ; i<k/2 ; i++) { right.offer(left.poll()); } double [] ans = new double [nums.length - k + 1 ]; ans[0 ] = getMid(k, left, right); for (int i=k; i<nums.length; i++) { int add = nums[i], del = nums[i-k]; if (add >= left.peek()) { left.offer(add); } else { right.offer(add); } if (del >= left.peek()) { left.remove(del); } else { right.remove(del); } adjust(left, right); ans[i - k + 1 ] = getMid(k, left, right); } return ans; } public void adjust (Queue<Integer> left, Queue<Integer> right) { while (right.size() > left.size()) { left.offer(right.poll()); } while (left.size() - 1 > right.size()) { right.offer(left.poll()); } } public double getMid (int k, Queue<Integer> left, Queue<Integer> right) { if (k % 2 == 0 ) { return left.peek() * 1.0 / 2 + right.peek() * 1.0 / 2 ; } else { return left.peek() * 1.0 ; } } }
注意 这个set不能重复,那么可以用map的值来记录个数,这个思想要记住。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution { public int lengthOfLongestSubstring (String s) { int ans = 0 ; int left = 0 ; Map<Character, Integer> map = new HashMap <>(); for (int right = 0 ; right<s.length(); right++) { char c = s.charAt(right); map.put(c, map.getOrDefault(c, 0 ) + 1 ); while (left <= right && map.get(c) > 1 ) { char temp = s.charAt(left); map.put(temp, map.getOrDefault(temp, 0 ) - 1 ); left += 1 ; } ans = Math.max(right - left + 1 , ans); } return ans; } }
注意: 这里面有一个经典,使用堆维护滑动窗口的最大值,那么存的时候同时存下标,下次取出最大值的时候如果根据下表判断不在滑动窗口内,则扔掉。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution { public int [] maxSlidingWindow(int [] nums, int k) { int n = nums.length; PriorityQueue<int []> queue = new PriorityQueue <>((a, b) -> b[0 ] - a[0 ]); int [] ans = new int [n - k + 1 ]; for (int i = 0 ; i < k-1 ; i ++) { queue.offer(new int []{nums[i], i}); } for (int i = k-1 ; i < n; i++) { queue.offer(new int []{nums[i], i}); while (queue.peek()[1 ] < i - k + 1 ) { queue.poll(); } ans[i-k+1 ] = (queue.peek()[0 ]); } return ans; } }
图论 拓扑排序,有向图的安全节点,环 ,或者看到每一次都有两两比较 的结果的。
在图论中,一个有向无环 图,必然存在至少一个拓扑序 与之对应,反之亦然。
能得到 某个有向无环图的拓扑序 前提是 必然能找到(至少)一个入度为0的点,使用BFS,在起始时将其入队。
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 class Solution { public int [] loudAndRich(int [][] richer, int [] quiet) { int n = quiet.length; List<Integer>[] g = new ArrayList [n]; int [] inCnts = new int [n]; int [] ans = new int [n]; for (int i = 0 ; i < n; i++) { g[i] = new ArrayList <>(); ans[i] = i; } for (int i = 0 ; i < richer.length; i++) { int a = richer[i][0 ], b = richer[i][1 ]; g[a].add(b); inCnts[b] += 1 ; } Deque<Integer> queue = new ArrayDeque <>(); for (int i = 0 ; i < n; i++) { if (inCnts[i] == 0 ) { queue.offerLast(i); } } while (!queue.isEmpty()) { int a = queue.pollFirst(); for (int b: g[a]) { inCnts[b] -= 1 ; if (inCnts[b] == 0 ) { queue.offerLast(b); } if (quiet[ans[b]] > quiet[ans[a]]) { ans[b] = ans[a]; } } } return 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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 class Solution { public int [][] buildMatrix(int k, int [][] rowConditions, int [][] colConditions) { int [] row = tuopu(k, rowConditions), col = tuopu(k, colConditions); if (row.length < k || col.length < k) { return new int [][]{}; } int [][] ans = new int [k][k]; int [] pos = new int [k + 1 ]; for (int i = 0 ; i < k; i++) { pos[row[i]] = i; } for (int i = 0 ; i < k; i++) { ans[pos[col[i]]][i] = col[i]; } return ans; } public int [] tuopu(int n, int [][] conditions) { List<Integer>[] g = new ArrayList [n + 1 ]; int [] inDe = new int [n + 1 ]; List<Integer> ans = new ArrayList <>(); for (int i = 0 ; i <= n; i++) { g[i] = new ArrayList <>(); } for (int [] edge: conditions) { int u = edge[0 ], v = edge[1 ]; g[u].add(v); inDe[v] += 1 ; } Deque<Integer> queue = new ArrayDeque <>(); for (int i = 1 ; i <= n; i++) { if (inDe[i] == 0 ) { queue.offerLast(i); } } while (!queue.isEmpty()) { int u = queue.pollFirst(); ans.add(u); for (int v: g[u]) { if (--inDe[v] == 0 ) { queue.offerLast(v); } } } return ans.stream().mapToInt(Integer::valueOf).toArray(); } }
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 class Solution { public boolean canFinish (int numCourses, int [][] prerequisites) { List<Integer>[] g = new ArrayList [numCourses]; int [] inDe = new int [numCourses]; List<Integer> ans = new ArrayList <>(); for (int i = 0 ; i < numCourses; i++) { g[i] = new ArrayList <>(); } for (int i = 0 ; i < prerequisites.length; i++) { int [] temp = prerequisites[i]; g[temp[1 ]].add(temp[0 ]); inDe[temp[0 ]] += 1 ; } Deque<Integer> queue = new ArrayDeque <>(); for (int i = 0 ; i < numCourses; i++) { if (inDe[i] == 0 ) { queue.offerLast(i); ans.add(i); } } while (!queue.isEmpty()) { int temp = queue.pollLast(); for (int nei: g[temp]) { inDe[nei] -= 1 ; if (inDe[nei] == 0 ) { queue.offerLast(nei); ans.add(nei); } } } return ans.size() == numCourses; } }
链表 链表模版 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 public class TemplateLianbiao { public static void main (String[] args) { Solution solution = new TemplateLianbiao ().new Solution (); } public class ListNode { int val; ListNode next; ListNode() {} ListNode(int val) { this .val = val; } ListNode(int val, ListNode next) { this .val = val; this .next = next; } } class Solution { public ListNode solve (ListNode l) { return new ListNode (); } } }
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 class Solution { public ListNode addTwoNumbers (ListNode l1, ListNode l2) { ListNode head = l1, pre = null ; int carry = 0 ; int value1 = 0 ; while (l1 != null && l2 != null ) { value1 = l1.val + l2.val + carry; l1.val = value1 % 10 ; carry = value1 / 10 ; pre = l1; l1 = l1.next; l2 = l2.next; } if (l2 != null ) { pre.next = l2; while (l2 != null ) { value1 = l2.val + carry; l2.val = value1 % 10 ; carry = value1 / 10 ; pre = l2; l2 = l2.next; } } else if (l1 != null ) { while (l1 != null ) { value1 = l1.val + carry; l1.val = value1 % 10 ; carry = value1 / 10 ; pre = l1; l1 = l1.next; } } if (carry == 1 ) { pre.next = new ListNode (1 ); } return head; } }
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 ListNode removeNthFromEnd (ListNode head, int n) { ListNode dummy = new ListNode (0 , head); ListNode right = head, left = dummy; for (int i=0 ; i<n; i++) { if (right == null ) { return head; } right = right.next; } while (right != null ) { right = right.next; left = left.next; } left.next = left.next.next; return dummy.next; } }
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 class Solution { public ListNode mergeKLists (ListNode[] lists) { ListNode dummy = new ListNode (); ListNode pre = dummy; PriorityQueue<ListNode> queue = new PriorityQueue <ListNode>((t1, t2) -> (t1.val - t2.val)); for (ListNode node: lists) { if (node != null ) { queue.offer(node); } } while (!queue.isEmpty()) { ListNode node = queue.poll(); pre.next = node; if (node.next != null ) { queue.offer(node.next); } pre = pre.next; } return dummy.next; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Solution { public ListNode reverseList (ListNode head) { ListNode prev = null ; ListNode cur = head; while (cur != null ) { ListNode temp = cur.next; cur.next = prev; prev = cur; cur = temp; } return prev; } }
先将链表闭合上,然后找到其中的点给他断开,然后考虑特殊情况。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution { public ListNode rotateRight (ListNode head, int k) { if (k == 0 || head == null || head.next == null ) { return head; } int n = 1 ; ListNode iter = head; while (iter.next != null ) { iter = iter.next; n++; } int add = n - k % n; if (add == n) { return head; } iter.next = head; while (add-- > 0 ) { iter = iter.next; } ListNode ret = iter.next; iter.next = null ; return ret; } }
或者跟之前一样先找到最后第k个,然后进行操作。
注意一下,删除的算法中,基本上都是,else的时候pre才会往后面移动的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution { public ListNode deleteDuplicates (ListNode head) { if (head == null ) return null ; ListNode start = head; while (head.next != null ) { if (head.val == head.next.val) { head.next = head.next.next; } else { head = head.next; } } return start; } }
注意一下,删除的算法中,基本上都是,else的时候pre才会往后面移动的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public ListNode deleteDuplicates (ListNode head) { ListNode dummyNode = new ListNode (-1 , head); ListNode node = dummyNode; while (node.next != null && node.next.next != null ) { if (node.next.val == node.next.next.val) { int x = node.next.val; while (node.next != null && node.next.val == x) { node.next = node.next.next; } } else { node = node.next; } } return dummyNode.next; } }
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 class Solution { public ListNode reverseBetween (ListNode head, int left, int right) { if (left == right) return head; ListNode preLeftNode = null , preRight = null , cur = head; for (int i=0 ; i<left-2 ; i++) { cur = cur.next; } preLeftNode = left == 1 ? null : cur; cur = left == 1 ? cur : cur.next; ListNode leftNode = cur; ListNode tempNext = cur.next; for (int i=left; i<right; i++) { ListNode temp = tempNext.next; tempNext.next = cur; cur = tempNext; tempNext = temp; } if (preLeftNode == null ) head = cur; else preLeftNode.next = cur; leftNode.next = tempNext; return head; } }
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 class Solution { public Node copyRandomList (Node head) { if (head == null ) { return null ; } Node start = head; while (head != null ) { Node node = new Node (head.val); node.next = head.next; head.next = node; head = head.next.next; } head = start; while (head != null ) { if (head.random != null ) { head.next.random = head.random.next; } head = head.next.next; } head = start; Node ans = head.next; while (head != null ) { Node temp = head.next; head.next = head.next.next; if (head.next != null ) { temp.next = head.next.next; } head = head.next; } return ans; } } public Node copyRandomList (Node head) { if (head == null ){ return null ; } Node cur = head; HashMap<Node,Node> map = new HashMap <>(); while (cur!=null ){ map.put(cur,new Node (cur.val)); cur = cur.next; } cur=head; while (cur!=null ){ map.get(cur).next=map.get(cur.next); map.get(cur).random=map.get(cur.random); cur=cur.next; } return map.get(head); }
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 public class Solution { public ListNode getIntersectionNode (ListNode headA, ListNode headB) { if (headA == null || headB == null ) { return null ; } ListNode ptr1 = headA, ptr2 = headB; while (ptr1 != ptr2) { if (ptr1 == null ) { ptr1 = headB; } else { ptr1 = ptr1.next; } if (ptr2 == null ) { ptr2 = headA; } else { ptr2 = ptr2.next; } } return ptr1; } }
注意一下,删除的算法中,基本上都是,else的时候pre才会往后面移动的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Solution { public ListNode removeElements (ListNode head, int val) { ListNode dummy = new ListNode (-1 , head); ListNode pre = dummy; while (pre.next != null ) { if (pre.next.val == val) { pre.next = pre.next.next; } else { pre = pre.next; } } return dummy.next; } }
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 class Solution { public ListNode[] splitListToParts(ListNode head, int k) { ListNode[] ans = new ListNode [k]; ListNode start = head; int length = 0 ; while (start != null ) { start = start.next; length += 1 ; } int num = length / k; int yu = length % k; for (int i=0 ; i<k; i++) { ans[i] = head; for (int j=0 ; j<num+(i>yu-1 ?0 :1 ) - 1 ; j++) { if (head != null ) { head = head.next; } else { break ; } } if (head != null ) { ListNode temp = head; head = head.next; temp.next = null ; } } return 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 class Solution { public ListNode mergeTwoLists (ListNode list1, ListNode list2) { ListNode dummy = new ListNode (); ListNode pre = dummy; while (list1 != null && list2 != null ) { if (list1.val < list2.val) { pre.next = list1; list1 = list1.next; } else { pre.next = list2; list2 = list2.next; } pre = pre.next; } if (list1 != null ) { pre.next = list1; } if (list2 != null ) { pre.next = list2; } return dummy.next; } }
归并排序
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 class Solution { public ListNode sortList (ListNode head) { return sortList(head, null ); } public ListNode sortList (ListNode head, ListNode tail) { if (head == null ) { return head; } if (head.next == tail) { head.next = null ; return head; } ListNode slow = head, fast = head; while (fast != tail) { fast = fast.next; slow = slow.next; if (fast != tail) { fast = fast.next; } } ListNode left = sortList(head, slow); ListNode right = sortList(slow, tail); return merge(left, right); } public ListNode merge (ListNode node1, ListNode node2) { ListNode dummy = new ListNode (-1 ); ListNode node = dummy; while (node1 != null && node2 != null ) { if (node1 != null && node2 != null ) { if (node1.val < node2.val) { node.next = node1; node1 = node1.next; } else { node.next = node2; node2 = node2.next; } } node = node.next; } if (node1 != null ) { node.next = node1; } if (node2 != null ) { node.next = node2; } return dummy.next; } }
其中一个链表的一部分删除,放入另外一个链表
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 class Solution { public ListNode mergeInBetween (ListNode list1, int a, int b, ListNode list2) { ListNode tail2 = list2, node = list1; int count = -1 ; while (tail2.next != null ) { tail2 = tail2.next; } while (node != null ) { count += 1 ; ListNode pre = node; node = node.next; if (count == a - 1 ) { pre.next = list2; } if (count == b) { tail2.next = node; } } return list1; } }
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 class Solution { public ListNode partition (ListNode head, int x) { ListNode dummySmall = new ListNode (-1 ); ListNode small = dummySmall; ListNode dummyLarge = new ListNode (-1 ); ListNode large = dummyLarge; while (head != null ) { if (head.val < x) { small.next = head; small = small.next; } else { large.next = head; large = large.next; } head = head.next; } large.next = null ; small.next = dummyLarge.next; return dummySmall.next; } }