Easy 两数之和 -哈希 跳转原题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Solution { public int [] twoSum(int [] nums, int target) { Map<Integer, Integer> map = new HashMap<>(); map.put(target - nums[0 ], 0 ); for (int i = 1 ; i < nums.length; i++){ if (map.containsKey(nums[i])){ return new int []{map.get(nums[i]), i}; } map.put(target - nums[i], i); } return new int []{}; } }
这题有点印象,所以一开始就用的 HashMap 去做。也可以用两层循环暴力去做。
移动零 - 双指针 跳转原题
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 void moveZeroes (int [] nums) { if (nums.length == 1 ){ return ; } int n = nums.length - 1 ; int i = 0 ; int j = 1 ; while (j < nums.length){ if (nums[i] != 0 ){ i++; j++; } else { if (nums[j] != 0 ){ nums[i] = nums[j]; nums[j] = 0 ; i++; j++; } else { j++; } } } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Solution { public void moveZeroes (int [] nums) { int n = nums.length, left = 0 , right = 0 ; while (right < n) { if (nums[right] != 0 ) { int temp = nums[left]; nums[left] = nums[right]; nums[right] = temp; left++; } right++; } } }
大体逻辑相同,区别在于我的解法是左右指针一开始就分开移动;而官方解法是一开始左右指针重叠移动,出现0元素时左右指针才会分开。
相交链表 - 链表 跳转原题
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 public class Solution { public ListNode getIntersectionNode (ListNode headA, ListNode headB) { Set<ListNode> set = new HashSet<>(); ListNode tempA = headA; ListNode tempB = headB; while (tempA != null || tempB != null ){ if (tempA != null ){ if (set.add(tempA)){ tempA = tempA.next; } else { return tempA; } } if (tempB != null ){ if (set.add(tempB)){ tempB = tempB.next; } else { return tempB; } } } return null ; } }
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 public class Solution { public ListNode getIntersectionNode (ListNode headA, ListNode headB) { if (headA == null || headB == null ){ return null ; } ListNode tempA = headA; ListNode tempB = headB; while (tempA != null || tempB != null ){ if (tempA == null ){ tempA = headB; } if (tempB == null ){ tempB = headA; } if (tempA == tempB){ return tempA; } tempA = tempA.next; tempB = tempB.next; } return null ; } }
反转链表 - 链表 跳转原题
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 class Solution { public ListNode reverseList (ListNode head) { if (head == null ){ return null ; } if (head.next == null ){ return head; } ListNode tempA = null ; ListNode tempB = head.next; while (head != null ){ head.next = tempA; tempA = head; head = tempB; if (tempB != null ){ tempB = tempB.next; } } return tempA; } }
1 2 3 4 5 6 7 8 9 10 11 12 class Solution { public ListNode reverseList (ListNode head) { if (head == null || head.next == null ) { return head; } ListNode newHead = reverseList(head.next); head.next.next = head; head.next = null ; return newHead; } }
简单说,迭代就是从头开始反转,递归就是从尾开始反转。
回文链表 - 链表 跳转原题
还有一种最简单的解法:把链表的值读到数组(ArrayList)里,然后用头尾双指针判断数组是否是回文即可。
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 class Solution { public boolean isPalindrome (ListNode head) { return check(head, head) == null ? false : true ; } public ListNode check (ListNode head, ListNode rear) { if (rear == null ){ return head; } ListNode nextHead = check(head, rear.next); if (nextHead == null || nextHead.val != rear.val){ return null ; } return head != rear ? nextHead.next : 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 class Solution { public boolean isPalindrome (ListNode head) { if (head == null ) { return true ; } ListNode firstHalfEnd = endOfFirstHalf(head); ListNode secondHalfStart = reverseList(firstHalfEnd.next); ListNode p1 = head; ListNode p2 = secondHalfStart; boolean result = true ; while (result && p2 != null ) { if (p1.val != p2.val) { result = false ; } p1 = p1.next; p2 = p2.next; } return result; } private ListNode reverseList (ListNode head) { ListNode prev = null ; ListNode curr = head; while (curr != null ) { ListNode nextTemp = curr.next; curr.next = prev; prev = curr; curr = nextTemp; } return prev; } private ListNode endOfFirstHalf (ListNode head) { ListNode fast = head; ListNode slow = head; while (fast.next != null && fast.next.next != null ) { fast = fast.next.next; slow = slow.next; } return slow; } }
环形链表 - 链表 跳转原题
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 public class Solution { public boolean hasCycle (ListNode head) { if (head == null ){ return false ; } ListNode fast = head; ListNode slow = head; while (fast.next != null && fast.next.next != null ){ fast = fast.next.next; slow = slow.next; if (fast == slow){ return true ; } } return false ; } }
遍历所有结点,如果有环,在回访到之前的结点时会发生哈希冲突。
1 2 3 4 5 6 7 8 9 10 11 12 public class Solution { public boolean hasCycle (ListNode head) { Set<ListNode> seen = new HashSet<ListNode>(); while (head != null ) { if (!seen.add(head)) { return true ; } head = head.next; } return false ; } }