思路一:
使用 HashMap
将 nums1
中的元素加入到 map 中并统计所有数字出现的次数
遍历 nums2
,若 nums2
中的元素在 map 中有,则将该元素加入到结果集中并且将 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 25 26 27 28 class Solution { public int [] intersect(int [] nums1, int [] nums2) { if (nums1.length > nums2.length) { return intersect(nums2,nums1); } Map<Integer, Integer> map = new HashMap <>(); for (int num: nums1) { int count = map.getOrDefault(num, 0 ) + 1 ; map.put(num, count); } int [] res = new int [nums1.length]; int index = 0 ; for (int num: nums2) { int count = map.getOrDefault(num, 0 ); if (count > 0 ) { res[index++] = num; count--; if (count > 0 ) { map.put(num, count); } else { map.remove(num); } } } return Arrays.copyOfRange(res, 0 , index); } }
思路二:
如果两个数组是有序的,则可以便捷地计算两个数组的交集。
首先对两个数组进行排序,然后使用两个指针遍历两个数组。
初始时,两个指针分别指向两个数组的头部。每次比较两个指针指向的两个数组中的数字,如果两个数字不相等,则将指向较小数字的指针右移一位,如果两个数字相等,将该数字添加到答案,并将两个指针都右移一位。当至少有一个指针超出数组范围时,遍历结束。
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 int [] intersect(int [] nums1, int [] nums2) { Arrays.sort(nums1); Arrays.sort(nums2); int length1 = nums1.length, length2 = nums2.length; int [] intersection = new int [Math.min(length1, length2)]; int index1 = 0 , index2 = 0 , index = 0 ; while (index1 < length1 && index2 < length2) { if (nums1[index1] < nums2[index2]) { index1++; } else if (nums1[index1] > nums2[index2]) { index2++; } else { intersection[index] = nums1[index1]; index1++; index2++; index++; } } return Arrays.copyOfRange(intersection, 0 , index); } }
解题思路: 使用递归,思路与求二叉树最大深度相似。
代码实现: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Solution { public int minDepth (TreeNode root) { if (root == null ) return 0 ; if (root.left == null && root.right == null ) return 1 ; if (root.left == null ) return minDepth(root.right) + 1 ; if (root.right == null ) return minDepth(root.left) + 1 ; return Math.min(minDepth(root.left), minDepth(root.right)) + 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 43 class Solution { public List<List<Integer>> generate (int numRows) { List<List<Integer>> triangle = new ArrayList <List<Integer>>(); if (numRows == 0 ) { return triangle; } triangle.add(new ArrayList <>()); triangle.get(0 ).add(1 ); for (int rowNum = 1 ; rowNum < numRows; rowNum++) { List<Integer> row = new ArrayList <>(); List<Integer> prevRow = triangle.get(rowNum-1 ); row.add(1 ); for (int j = 1 ; j < rowNum; j++) { row.add(prevRow.get(j-1 ) + prevRow.get(j)); } row.add(1 ); triangle.add(row); } return triangle; } }
解题方法一:暴力枚举法 使用 嵌套循环遍历数组,列出所有可能的收益,从中找到最大的作为结果返回
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 public class Solution { public int maxProfit (int [] prices) { int len = prices.length; if (len < 2 ) { return 0 ; } int res = 0 ; for (int i = 0 ; i < len - 1 ; i++) { for (int j = i + 1 ; j < len; j++) { res = Math.max(res, prices[j] - prices[i]); } } return res; } }
解题方法二:暴力算法的优化 只需要关心之前看到的最低价格,用一个变量记录下之前的最低价格,这样可以省去内层循环
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 public class Solution { public int maxProfit (int [] prices) { int len = prices.length; if (len < 2 ) { return 0 ; } int res = 0 ; int minVal = prices[0 ]; for (int i = 1 ; i < len; i++) { res = Math.max(res, prices[i] - minVal); minVal = Math.min(minVal, prices[i]); } return res; } }
解体方法一:哈希表 我们使用 HashSet
来存储每个访问过的节点的引用,如果该节点出现在 HashSet
中,则说明链表为环形链表。
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 public boolean hasCycle (ListNode head) { Set<ListNode> nodesSeen = new HashSet <>(); while (head != null ) { if (nodesSeen.contains(head)) { return true ; } else { nodesSeen.add(head); } head = head.next; } 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 public boolean hasCycle (ListNode head) { if (head == null || head.next == null ) { return false ; } ListNode slow = head; ListNode fast = head.next; while (slow != fast) { if (fast == null || fast.next == null ) { return false ; } slow = slow.next; fast = fast.next.next; } return true ; }
解法一: 更改底层数据结构,设计一个 MinStackNode 类,类中每个节点用来存放值和当前栈中的最小值。
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 class MinStack { LinkedList<MinStackNode> stack; public MinStack () { stack = new LinkedList <>(); } public void push (int x) { if (stack.size() > 0 ) { int preMin = stack.getLast().min; int min = Math.min(x, preMin); stack.add(new MinStackNode (x, min)); } else { stack.add(new MinStackNode (x, x)); } } public void pop () { stack.removeLast(); } public int top () { return stack.getLast().value; } public int getMin () { return stack.getLast().min; } } class MinStackNode { int value; int min; public MinStackNode (int value, int min) { this .value = value; this .min = min; } }
解法二: 设计一个辅助栈,用来保存最小值,如果 pop()
的值刚好是最小值,那么同时将辅助栈的栈顶也 pop()
了
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 MinStack { private Stack<Integer> dataStack; private Stack<Integer> minStack; public MinStack () { dataStack = new Stack <>(); minStack = new Stack <>(); } public void push (int x) { dataStack.push(x); if (minStack.isEmpty() || x <= minStack.peek()) { minStack.push(x); } } public void pop () { int x = dataStack.pop(); if (x == minStack.peek()) { minStack.pop(); } } public int top () { return dataStack.peek(); } public int getMin () { return minStack.peek(); } }