刷題記錄之LeetCode001-200Java版(詳細註釋)

目錄

1. Two Sum

2. Add Two Numbers

3. Longest Substring Without Repeating Characters

4. Median of Two Sorted Arrays

5. Longest Palindromic Substring

11. Container With Most Water

15. 3Sum

17. Letter Combinations of a Phone Number

18. 4Sum

19. Remove Nth Node From End of List

20. Valid Parentheses

21. Merge Two Sorted Lists

22. Generate Parentheses

24. Swap Nodes in Pairs

25. K個一組翻轉鏈表

31. Next Permutation

33. Search in Rotated Sorted Array

34. Find First and Last Position of Element in Sorted Array

39. Combination Sum

46. Permutations

48. Rotate Image

49. Group Anagrams

53. Maximum Subarray

55. Jump Game

56. Merge Intervals

62. Unique Paths

63. 不同路徑2

64. Minimum Path Sum

75. Sort Colors

78. Subsets

79. Word Search

81. Search in Rotated Sorted Array II

94. Binary Tree Inorder Traversal

95. 不同的二叉搜索樹 II

96. Unique Binary Search Trees

98. Validate Binary Search Tree

101. Symmetric Tree

102. Binary Tree Level Order Traversal

104. Maximum Depth of Binary Tree

105. Construct Binary Tree from Preorder and Inorder Traversal

114. Flatten Binary Tree to Linked List

121. Best Time to Buy and Sell Stock

128. 最長連續序列

129. 求根到葉子節點數字之和

136. Single Number

138. 複製帶隨機指針的鏈表

139. Word Break

141. Linked List Cycle

142. Linked List Cycle II

148. Sort List

152. Maximum Product Subarray

169. Majority Element

198. House Robber

200. 島嶼數量

 


1. Two Sum

Given an array of integers, return indices of the two numbers such that they add up to a specific target.

You may assume that each input would have exactly one solution, and you may not use the same element twice.

Example:

Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

class Solution {
    public int[] twoSum(int[] nums, int target) {
        //一個HashMap解決
        HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
        for(int i = 0; i < nums.length; i++) {
            if(map.containsKey(target - nums[i]))
                return new int[]{map.get(target - nums[i]), i};
            map.put(nums[i], i);
        }
        return null;
    }
}

2. Add Two Numbers

You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.

You may assume the two numbers do not contain any leading zero, except the number 0 itself.

Example:

Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807.

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode head = l1;  //head doesn't change
        ListNode tail = head;  //tail is the last completed Node, always not null
        int a = 0;  //進位標記
        
        while(l1 != null && l2 != null){
            l1.val += (l2.val + a);
            if(l1.val >= 10){
                a = 1;
                l1.val -= 10;
            }
            else a = 0;
            tail = l1;
            l1 = l1.next;
            l2 = l2.next;
        }
        
        if(l2 != null)
            tail.next = l2;
        
        while(tail.next != null){  //a爲0退出,否則繼續加下去
            tail.next.val += a;
            if(tail.next.val >= 10){
                a = 1;
                tail.next.val -= 10;
            }
            else{
                a = 0;
                break;
            }
            tail = tail.next;
        }
        
        if(a == 1){  //新進一位
            ListNode last = new ListNode(1);
            tail.next = last;
        }
        
        return head;
    }
}

3. Longest Substring Without Repeating Characters

Given a string, find the length of the longest substring without repeating characters.

Example 1:

Input: "abcabcbb"
Output: 3 
Explanation: The answer is "abc", with the length of 3. 
Example 2:

Input: "bbbbb"
Output: 1
Explanation: The answer is "b", with the length of 1.
Example 3:

Input: "pwwkew"
Output: 3
Explanation: The answer is "wke", with the length of 3. 
             Note that the answer must be a substring, "pwke" is a subsequence and not a substring.

class Solution {
    public int lengthOfLongestSubstring(String s) {
        HashMap map = new HashMap();
        int max = 0, start = 0;
        for(int i = 0; i < s.length(); i++){
            if(s.length() - start <= max) break;
            //發現重複時,只有重複字符的下一位>start時才需要更新start
            if(map.containsKey(s.charAt(i)))
                start = Math.max(start, (int)map.get(s.charAt(i)) + 1);
            max = Math.max(max, i - start + 1);
            map.put(s.charAt(i),i);
        }
        return max;
    }
}

4. Median of Two Sorted Arrays

There are two sorted arrays nums1 and nums2 of size m and n respectively.

Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

You may assume nums1 and nums2 cannot be both empty.

Example 1:

nums1 = [1, 3]
nums2 = [2]

The median is 2.0

Example 2:

nums1 = [1, 2]
nums2 = [3, 4]

The median is (2 + 3)/2 = 2.5

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m = nums1.length;
        int n = nums2.length;
        if((m + n) % 2 == 1)  //合併後總長度爲奇數
            return findKthSmall(nums1, 0, nums2, 0, (m + n) / 2 + 1) * 1.0;
        else  //合併後總長度爲偶數
            return (findKthSmall(nums1, 0, nums2, 0, (m + n) / 2) 
                    + findKthSmall(nums1, 0, nums2, 0, (m + n) / 2 + 1)) / 2.0;
    }
    //尋找兩個數組合並後的第k小元素
    public int findKthSmall(int[] nums1, int start1, int[] nums2, int start2, int k) {
        if(start1 >= nums1.length)
            return nums2[start2 + k - 1];
        if(start2 >= nums2.length)
            return nums1[start1 + k - 1];
        if(k == 1)  //遞歸出口,直接返回首元素中更小的
            return Math.min(nums1[start1], nums2[start2]);
        
        //每次扣除k/2個比目標值小的元素,通過比較兩個數組的前k/2個元素,決定從哪個數組中扣除
        //本數組長度不夠數k/2個時,無論本數組的值如何,另一個數組的前k/2個都必定小於目標值可扣除
        //因此本數組的mid賦值爲MAX_VALUE,以便於全部留下
        //mid是指數組第k/2個元素,而不是數組長度的mid
        int mid1 = start1 + k / 2 - 1 >= nums1.length ? Integer.MAX_VALUE : nums1[start1 + k / 2 - 1];
        int mid2 = start2 + k / 2 - 1 >= nums2.length ? Integer.MAX_VALUE : nums2[start2 + k / 2 - 1];
        if(mid1 < mid2)  //更小的mid說明start到mid都小於目標值,可扣除
            return findKthSmall(nums1, start1 + k / 2, nums2, start2, k - k / 2);
        else
            return findKthSmall(nums1, start1, nums2, start2 + k / 2, k - k / 2);
    }
}

5. Longest Palindromic Substring

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.

Example 1:

Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.
Example 2:

Input: "cbbd"
Output: "bb"

class Solution {
    public String longestPalindrome(String s) {
        int[] start = new int[]{0};
        int[] max = new int[]{0};
        //每個位置都作爲子串中心點調用一次函數,分奇數和偶數個字符兩種情況
        for(int i = 0; i < s.length(); i++) {
            extendPalindromic(s, i, i, max, start);
            extendPalindromic(s, i, i + 1, max, start);
        }
        return s.substring(start[0], start[0] + max[0]);
    }
    //以j和k作爲中心點向兩側延伸,更新最大長度max[0]和起始位置start[0]
    public void extendPalindromic(String s, int j, int k, int[] max, int[] start) {
        while(j >= 0 && k < s.length() && s.charAt(j) == s.charAt(k)) {
            j--;
            k++;
        }
        if(k - j - 1 > max[0]) {
            start[0] = j + 1;
            max[0] = k - j - 1;
        }
    } 
}

11. Container With Most Water

Given n non-negative integers a1a2, ..., an , where each represents a point at coordinate (iai). n vertical lines are drawn such that the two endpoints of line i is at (iai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.

Note: You may not slant the container and n is at least 2.

The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue section) the container can contain is 49.

class Solution {
    public int maxArea(int[] height) {
        int max = 0;
        int start = 0, end = height.length - 1;
        while(start < end) {
            //計算容積,並更新max
            max = Math.max(max, (end - start) * Math.min(height[start], height[end]));
            if(height[start] < height[end])  //每次都拋棄更矮的邊
                start++;
            else 
                end--;
        }
        return max;
    }
}

15. 3Sum

Given an array nums of n integers, are there elements abc in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note:

The solution set must not contain duplicate triplets.

Example:

Given array nums = [-1, 0, 1, 2, -1, -4],

A solution set is:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> result = new ArrayList();
        Arrays.sort(nums);  //排序升序
        for(int i = 0; i < nums.length - 2; i++) {
            //跳過已經遍歷過的nums[i - 1],保證第一個值不重複
            if(i > 0 && nums[i] == nums[i - 1])  
                continue;
            int j = i + 1, k = nums.length - 1;
            while(j < k) {
                int sum = nums[i] + nums[j] + nums[k];
                if(sum == 0) {
                    result.add(Arrays.asList(nums[i], nums[j], nums[k]));   
                    j++;
                    k--;
                    //(只需在sum等於0時)保證第二、三個值不重複
                    while(j < k && nums[j] == nums[j - 1])
                        j++;
                    while(j < k && nums[k] == nums[k + 1])
                        k--;
                }
                else if(sum > 0)
                    k--;
                else
                    j++;
            }
        }
        return result;
    }
}

17. Letter Combinations of a Phone Number

Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent.

A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.

Example:

Input: "23"

Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].

Note:

Although the above answer is in lexicographical order, your answer could be in any order you want.

class Solution {
    public List<String> letterCombinations(String digits) {
        List<String> result = new ArrayList<String>();
        if(digits.length() == 0)
            return result;
        
        char[][] letters = new char[][]{
            {'a', 'b', 'c'},
            {'d', 'e', 'f'},
            {'g', 'h', 'i'},
            {'j', 'k' ,'l'},
            {'m', 'n', 'o'},
            {'p', 'q', 'r', 's'},
            {'t', 'u', 'v'},
            {'w', 'x', 'y', 'z'},
        };

        result.add("");
        
        for(int i = 0; i < digits.length(); i++) {
            int number = digits.charAt(i) - '0';
            if(number < 2 || number > 9)
                continue;
            result = addOneLetter(result, letters[number - 2]);
        }
        
        return result;       
    }

    //添加一個字母,參數爲需要改動的strArr和1個數字代表的字母列表
    public List<String> addOneLetter(List<String> strArr, char[] charArr) {
        //按添加一個字母后的長度初始化String[]
        String[] result = new String[strArr.size() * charArr.length];
        
        int i = 0, j = 0, k = 0;  //分別爲result下標,原strArr下標,字母列表下標
        while(i < result.length) {
            result[i] = new String(strArr.get(j)) + charArr[k];
            
            i++;
            if(i % charArr.length == 0)
                j++;
            k = (k + 1) % charArr.length;
        }
        return Arrays.asList(result);
    }
}

18. 4Sum

Given an array nums of n integers and an integer target, are there elements abc, and din nums such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.

Note:

The solution set must not contain duplicate quadruplets. A solution set is: [ [-1, 0, 0, 1], [-2, -1, 1, 2], [-2, 0, 0, 2] ]

Example:

Given array nums = [1, 0, -1, 0, -2, 2], and target = 0.

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        if(nums.length < 4)
            return result;
        //對後3個數和3sum相同,只不過判斷sum == 0 改爲 == target - nums[i]
        Arrays.sort(nums);
        int n = nums.length;
        for(int i = 0; i < n - 3; i++) {
            //前面的和太大,跳出循環
            if(nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target)
                break;
            //後面的和還不夠,繼續下一次
            if(nums[i] + nums[n - 1] + nums[n - 2] + nums[n - 3] < target)
                continue;
            if(i > 0 && nums[i] == nums[i - 1])
                continue;
            for(int j = i + 1; j < n - 2; j++) {
                if(nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target)
                    break;
                if(nums[i] + nums[j] + nums[n - 1] + nums[n - 2] < target)
                    continue;
                if(j > i + 1 && nums[j] == nums[j - 1])
                    continue;
                int k = j + 1, l = n - 1;
                while(k < l) {  //對後兩個數開始用while循環
                    int sum = nums[j] + nums[k] + nums[l];
                    if(sum == target - nums[i]) {
                        result.add(Arrays.asList(nums[i], nums[j], nums[k], nums[l]));
                        while(k < l && nums[k] == nums[k + 1])
                            k++;
                        while(k < l && nums[l] == nums[l - 1])
                            l--;
                        k++;
                        l--;
                    }
                    else if(sum > target - nums[i])
                        l--;
                    else
                        k++;
                }
            }
        }
        return result;
    }
}

19. Remove Nth Node From End of List

Medium

1959146FavoriteShare

Given a linked list, remove the n-th node from the end of list and return its head.

Example:

Given linked list: 1->2->3->4->5, and n = 2.

After removing the second node from the end, the linked list becomes 1->2->3->5.

Note:

Given n will always be valid.

Follow up:

Could you do this in one pass?

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode l1 = head, l2 = head;
        int i;
        for(i = 0; i < n && l1.next != null; i++)  //l1先移動n步
            l1 = l1.next;
        while(l1.next != null){  //l1移動到最後一個節點,此時l2.next爲需要刪除的節點
            l1 = l1.next;
            l2 = l2.next;
        }
        if(i == n){  //說明l1成功地先移動了n步,n合理,可以刪除l2.next
            l1 = l2.next.next;
            l2.next = l1;
        }
        else head = head.next;  //否則刪掉頭節點
        return head;
    }
}

20. Valid Parentheses

Given a string containing just the characters '('')''{''}''[' and ']', determine if the input string is valid.

An input string is valid if:

1.Open brackets must be closed by the same type of brackets.
2.Open brackets must be closed in the correct order.

Note that an empty string is also considered valid.

Example 1:

Input: "()"

Output: true

Example 2:

Input: "()[]{}"

Output: true

Example 3:

Input: "(]"

Output: false

Example 4:

Input: "([)]"

Output: false

Example 5:

Input: "{[]}"

Output: true

class Solution {
    public boolean isValid(String s) {
        //一個棧解決
        Stack stack = new Stack();
        for(int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            switch(c) {
                case ')':
                    if(stack.empty() || (char)stack.pop() != '(')
                        return false;
                    break;
                case ']':
                    if(stack.empty() || (char)stack.pop() != '[')
                        return false;
                    break;
                case '}':
                    if(stack.empty() || (char)stack.pop() != '{')
                        return false;
                    break;
                default:
                    stack.push(c);
            }
        }
        if(stack.empty())
            return true;
        else
            return false;
    }
}

21. Merge Two Sorted Lists

Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.

Example:

Input: 1->2->4, 1->3->4

Output: 1->1->2->3->4->4

class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        //偷懶用遞歸解決
        if(l1 == null) return l2;
		if(l2 == null) return l1;
		if(l1.val <= l2.val) {
            l1.next = mergeTwoLists(l1.next, l2);
            return l1;
        }
        else {
            l2.next = mergeTwoLists(l1, l2.next);
            return l2;
        }
    }
}

22. Generate Parentheses

Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.

For example, given n = 3, a solution set is:

[
  "((()))",
  "(()())",
  "(())()",
  "()(())",
  "()()()"
]

class Solution {
    public List<String> generateParenthesis(int n) {
        List<String> result = new ArrayList<String>();
        
        backtrack(result, "", 0, 0, n);
        return result;
    }
    //回溯算法
    public void backtrack(List<String> result, String s, int numOpen, int numClose, int n) {
        if(s.length() == 2 * n){
            result.add(s);
            return;
        }
        //先判斷能否加'('
        if(numOpen < n)
            backtrack(result, s + "(", numOpen + 1, numClose, n);
        //再判斷能否加')'
        if(numClose < numOpen)
            backtrack(result, s + ")", numOpen, numClose + 1, n);
    }
}

24. Swap Nodes in Pairs

Given a linked list, swap every two adjacent nodes and return its head.

You may not modify the values in the list's nodes, only nodes itself may be changed.

Example:
Given 1->2->3->4, you should return the list as 2->1->4->3.

class Solution {
    public ListNode swapPairs(ListNode head) {
        //先判斷長度是否>=2
        int n = 0;
        for(ListNode r = head; r != null && n < 2; r = r.next) n++;
        if(n < 2) 
            return head;
        else{  //遞歸即可
            ListNode r = head.next.next;
            ListNode start = head.next;
            head.next.next = head;
            head.next = swapPairs(r);
            return start;
        }
    }
}

25. K個一組翻轉鏈表

給你一個鏈表,每 k 個節點一組進行翻轉,請你返回翻轉後的鏈表。

k 是一個正整數,它的值小於或等於鏈表的長度。

如果節點總數不是 k 的整數倍,那麼請將最後剩餘的節點保持原有順序。

示例 :

給定這個鏈表:1->2->3->4->5

當 k = 2 時,應當返回: 2->1->4->3->5

當 k = 3 時,應當返回: 3->2->1->4->5

說明 :
你的算法只能使用常數的額外空間。
你不能只是單純的改變節點內部的值,而是需要實際的進行節點交換。

class Solution {
    public ListNode reverse(ListNode head) {
        ListNode tail = null;
        while(head != null) {
            ListNode temp = head.next;
            head.next = tail;
            tail = head;
            head = temp;
        }
        return tail;
    }
    public ListNode reverseKGroup(ListNode head, int k) {
        //先翻轉前k個,再遞歸
        ListNode p = head;
        ListNode pre = null;
        int i = 0;
        for(; i < k && p != null; i++) {
            pre = p;
            p = p.next;
        }
        //長度不夠k
        if(i < k) {
            return head;
        }
        //斷開並翻轉
        pre.next = null;
        ListNode res = reverse(head);
        //翻轉後head即尾節點,連接遞歸的後續部分
        head.next = reverseKGroup(p, k);
        
        return res;
    }
}

31. Next Permutation

Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.

If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).

The replacement must be in-place and use only constant extra memory.

Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.

1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1

class Solution {
    public void nextPermutation(int[] nums) {
        if(nums == null || nums.length <= 1)
            return;
        
        //思路是把臨界元素置換成下一個更大的元素,再把逆序的後半段變成升序
        
        int i = nums.length - 2;
        while(i >= 0 && nums[i] >= nums[i + 1])  //跳過結尾逆序,找到第一個順序對的前者nums[i]
            i--;
        if(i >= 0) {
            int j = nums.length - 1;
            while(nums[j] <= nums[i])  //從後向前找到第一個比nums[i]大的
                j--;
            int temp = nums[i];  //和nums[i]交換
            nums[i] = nums[j];
            nums[j] = temp;
        }
        //i + 1到結尾全部反轉(變成升序)
        for(int j = i + 1, k = nums.length - 1; j <= k; j++, k--) {
            int temp = nums[j];
            nums[j] = nums[k];
            nums[k] = temp;
        }
        
    }
}

33. Search in Rotated Sorted Array

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.

(i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]).

You are given a target value to search. If found in the array return its index, otherwise return -1.

You may assume no duplicate exists in the array.

Your algorithm's runtime complexity must be in the order of O(log n).

Example 1:
Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4

Example 2:
Input: nums = [4,5,6,7,0,1,2], target = 3
Output: -1

class Solution {
    public int search(int[] nums, int target) {
        int start = 0, end = nums.length - 1;
        while(start <= end) {
            int mid = (start + end) / 2;
            if(nums[mid] == target)
                return mid;
            if(nums[start] < nums[end]) {  //整個都是升序時正常二分查找
                if(target < nums[mid])
                    end = mid - 1;
                else
                    start = mid + 1;
            }
            //半邊是隻包括mid的部分
            else if(nums[mid] >= nums[start]) {  //左半邊是升序,mid可能等於start所以要加上=
                if(target > nums[mid]) {  //比nums[mid]大的一定在右邊
                    start = mid + 1;
                }
                else {  //比nums[mid]小,分兩種情況
                    if(target >= nums[start])  //target在左半邊
                        end = mid - 1;
                    else  //target在右半邊
                        start = mid + 1;
                }
            }
            else {  //右半邊是升序
                if(target < nums[mid]) {  //比nums[mid]小的一定在左邊
                    end = mid - 1;
                }
                else {  //比nums[mid]大,分兩種情況
                    if(target <= nums[end])  //target在右半邊
                        start = mid + 1;
                    else  //target在左半邊
                        end = mid - 1;
                }
            }
        }      
        return -1;
    }
}

34. Find First and Last Position of Element in Sorted Array

Given an array of integers nums sorted in ascending order, find the starting and ending position of a given target value.

Your algorithm's runtime complexity must be in the order of O(log n).

If the target is not found in the array, return [-1, -1].

Example 1:

Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]

Example 2:

Input: nums = [5,7,7,8,8,10], target = 6
Output: [-1,-1]

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] result = new int[]{-1, -1};
        //先二分查找
        int start = 0, end = nums.length - 1;
        int mid = (start + end) / 2;
        while(start <= end) {            
            if(nums[mid] == target) {
                result[0] = mid;
                result[1] = mid;
                break;
            }
            else if(nums[mid] < target) {
                start = mid + 1;
            }
            else {
                end = mid - 1;
            }
            mid = (start + end) / 2;
        }
        //如果找到,則向兩側遍歷找到兩端下標
        if(result[0] != -1) {
            int i = result[0], j = result[1];
            while(i >= start && nums[i] == target) i--;  //注意先判斷i>=start
            result[0] = i + 1;
            while(j <= end && nums[j] == target) j++;
            result[1] = j - 1;
        }
        return result;
    }
}

39. Combination Sum

Given a set of candidate numbers (candidates(without duplicates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.

The same repeated number may be chosen from candidates unlimited number of times.

Note:

All numbers (including target) will be positive integers.
The solution set must not contain duplicate combinations.

Example 1:
Input: candidates = [2,3,6,7], target = 7,
A solution set is:
[
  [7],
  [2,2,3]
]

Example 2:
Input: candidates = [2,3,5], target = 8,
A solution set is:
[
  [2,2,2,2],
  [2,3,3],
  [3,5]
]

class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> list = new ArrayList<>();
        Arrays.sort(candidates);
        backtrack(list, new ArrayList<>(), candidates, target, 0);
        return list;
    }
    //回溯算法搞定
    private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] candidates, int remain, int start) {
        if(remain < 0) 
            return;
        else if(remain == 0) 
            list.add(new ArrayList<>(tempList));  //注意是new ArrayList複製一個新的纔對
        else { 
            for(int i = start; i < candidates.length; i++) {
                tempList.add(candidates[i]);
                //因爲元素可以重複使用,所以最後一個參數start還是i
                backtrack(list, tempList, candidates, remain - candidates[i], i); 
                tempList.remove(tempList.size() - 1);
                //可以看到tempList的add和remove是成對的,循環進行一次tempList長度不變
                //即使中間有遞歸調用也不會影響
            }
        }
    }
}

46. Permutations

Given a collection of distinct integers, return all possible permutations.

Example:

Input: [1,2,3]
Output:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        result.add(new ArrayList<Integer>());
        for(int i = 0; i < nums.length; i++) {
            addOneNum(nums, i, result);  //插入第i個數,第二個參數傳下標i(要用到)
        }
        return result;
    }
    //不過這個循環結果不是例子那樣
    private void addOneNum(int[] nums, int i, List<List<Integer>> result) {
        int size1 = result.size();
        int size2 = i;
        //原來的每個序列都會變爲 size2+1 個新序列
        for(int j = 0; j < size1; j++) {  //j * (size2 + 1) is the right index to add
            //取出舊序列,並從result移除
            List<Integer> tempList = result.get(j * (size2 + 1));
            result.remove(j * (size2 + 1));
            //新元素nums[i]可以插入的位置有 size2+1 個
            for(int k = 0; k < size2 + 1; k++) {
                List<Integer> newList = new ArrayList<Integer>(tempList);
                newList.add(k, nums[i]);
                result.add(j * (size2 + 1), newList);
            }
        }
    }
}

48. Rotate Image

You are given an n x n 2D matrix representing an image.

Rotate the image by 90 degrees (clockwise).

Note:

You have to rotate the image in-place, which means you have to modify the input 2D matrix directly. DO NOT allocate another 2D matrix and do the rotation.

Example 1:
Given input matrix = 
[
  [1,2,3],
  [4,5,6],
  [7,8,9]
],
rotate the input matrix in-place such that it becomes:
[
  [7,4,1],
  [8,5,2],
  [9,6,3]
]

Example 2:
Given input matrix =
[
  [ 5, 1, 9,11],
  [ 2, 4, 8,10],
  [13, 3, 6, 7],
  [15,14,12,16]
], 
rotate the input matrix in-place such that it becomes:
[
  [15,13, 2, 5],
  [14, 3, 4, 1],
  [12, 6, 8, 9],
  [16, 7,10,11]
]

class Solution {
    public void rotate(int[][] matrix) {
        for(int i = 0; i < matrix.length / 2; i++) {  //圈數
            for(int j = i; j < matrix[i].length - i - 1; j++) {
                int temp = matrix[i][j];
                //每次4個數旋轉90度
                matrix[i][j] = matrix[matrix.length - 1 - j][i];
                matrix[matrix.length - 1 - j][i] = 
                    matrix[matrix.length - 1 - i][matrix.length - 1 - j];
                matrix[matrix.length - 1 - i][matrix.length - 1 - j] = 
                    matrix[j][matrix.length - 1 - i];
                matrix[j][matrix.length - 1 - i] = temp;
            }
        }
    }
}

49. Group Anagrams

Given an array of strings, group anagrams together.

Example:
Input: ["eat", "tea", "tan", "ate", "nat", "bat"],
Output:
[
  ["ate","eat","tea"],
  ["nat","tan"],
  ["bat"]
]

Note:
All inputs will be in lowercase.
The order of your output does not matter.

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        if (strs == null || strs.length == 0) 
            return new ArrayList<List<String>>();
        //用一個HashMap解決,最後用map.values()獲得value集合
        Map<String, List<String>> map = new HashMap<String, List<String>>();
        for (String s : strs) {
            char[] ca = s.toCharArray();
            Arrays.sort(ca);
            String keyStr = String.valueOf(ca);
            if (!map.containsKey(keyStr)) 
                map.put(keyStr, new ArrayList<String>());
            map.get(keyStr).add(s);
        }
        return new ArrayList<List<String>>(map.values());
    }
}

53. Maximum Subarray

Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.

Example:
Input: [-2,1,-3,4,-1,2,1,-5,4],
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.

Follow up:
If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.

class Solution {
    public int maxSubArray(int[] nums) {
        if(nums.length == 0) return 0;
        int maxSum = Integer.MIN_VALUE;
        int sum = 0;
        for(int i = 0; i < nums.length; i++){
            //每個sum都要求包含當前nums[i]
            if(sum < 0) sum = nums[i];  //舊的sum爲負數,則拋棄
            else sum += nums[i];
            maxSum = Math.max(sum, maxSum);
        }
        return maxSum;
    }
}

55. Jump Game

Given an array of non-negative integers, you are initially positioned at the first index of the array.

Each element in the array represents your maximum jump length at that position.

Determine if you are able to reach the last index.

Example 1:
Input: [2,3,1,1,4]
Output: true
Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.

Example 2:
Input: [3,2,1,0,4]
Output: false
Explanation: You will always arrive at index 3 no matter what. Its maximum
             jump length is 0, which makes it impossible to reach the last index.

class Solution {
    public boolean canJump(int[] nums) {
        int max = 0;  //max爲當前可到達的最遠處
        for(int i = 0; i < nums.length; i++){
            if(max < i) return false;  //當前i無法到達,返回false
            max = Math.max(max, i + nums[i]);
        }
        return true;
    }
}

56. Merge Intervals

Given a collection of intervals, merge all overlapping intervals.

Example 1:
Input: [[1,3],[2,6],[8,10],[15,18]]
Output: [[1,6],[8,10],[15,18]]
Explanation: Since intervals [1,3] and [2,6] overlaps, merge them into [1,6].

Example 2:
Input: [[1,4],[4,5]]
Output: [[1,5]]
Explanation: Intervals [1,4] and [4,5] are considered overlapping.

class Solution {
    public int[][] merge(int[][] intervals) {
        //區間合併的關鍵點在於start和end分別排序,再合併結果相同
        int n = intervals.length;
        int[] starts = new int[n];
        int[] ends = new int[n];
        for (int i = 0; i < n; i++) {  //保存starts和ends數組
            starts[i] = intervals[i][0];
            ends[i] = intervals[i][1];
        }
        //分別排序
        Arrays.sort(starts);
        Arrays.sort(ends);

        int[][] res = new int[intervals.length][2];
        int k = 0;  //res的下標
        for (int i = 0, j = 0; i < n; i++) {  // j is start of interval.
            if (i == n - 1 || starts[i + 1] > ends[i]) {  //分割點
                res[k++] = new int[]{starts[j], ends[i]};
                j = i + 1;
            }
        }
        return Arrays.copyOf(res, k);
    }
}

62. Unique Paths

A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below).

The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below).

How many possible unique paths are there?


Above is a 7 x 3 grid. How many possible unique paths are there?

Note: m and n will be at most 100.

Example 1:
Input: m = 3, n = 2
Output: 3
Explanation:
From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
1. Right -> Right -> Down
2. Right -> Down -> Right
3. Down -> Right -> Right

Example 2:
Input: m = 7, n = 3
Output: 28

class Solution {
    public int uniquePaths(int m, int n) {
        //m - 1 個 right, n - 1 個 down
        //m + n - 2 個數中取 n - 1個 down
        int max = Math.max(m, n);
        int min = Math.min(m, n);
        if(min == 1)
            return 1;
        //組合數計算公式(取min - 1個,計算更快)
        long result = 1;
        for(int i = max + min - 2; i > max - 1; i--)
            result *= i;
        return (int)(result / factorial(min - 1));
    }
    public int factorial(int x) {
        for(int i = x - 1; i > 0; i--)
            x *= i;
        return x;
    }
}

63. 不同路徑2

一個機器人位於一個 m x n 網格的左上角 (起始點在下圖中標記爲“Start” )。

機器人每次只能向下或者向右移動一步。機器人試圖達到網格的右下角(在下圖中標記爲“Finish”)。

現在考慮網格中有障礙物。那麼從左上角到右下角將會有多少條不同的路徑?

網格中的障礙物和空位置分別用 1 和 0 來表示。

說明:m 和 n 的值均不超過 100。

示例 1:

輸入:
[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]
輸出: 2

解釋:
3x3 網格的正中間有一個障礙物。
從左上角到右下角一共有 2 條不同的路徑:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右

class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        //新矩陣每個元素表示起點到此的路徑數,上邊和左邊一律是1,再由相鄰元素求出所有元素
        //矩陣路徑問題一律用此方法
        //這道不需要新建矩陣,直接在原矩陣上修改就可
        for(int i = 0; i < obstacleGrid.length; i++) {
            for(int j = 0; j < obstacleGrid[0].length; j++) {
                //障礙不可到達,需要先判斷以便預防終點是障礙的情況
                if(obstacleGrid[i][j] == 1) {
                    obstacleGrid[i][j] = 0;
                }
                //否則若是起點,路徑數爲1
                else if(i == 0 && j == 0) {
                    obstacleGrid[i][j] = 1;
                }
                //上邊和左邊
                else if(i == 0 || j == 0){
                    obstacleGrid[i][j] = i == 0 ? obstacleGrid[i][j-1] : obstacleGrid[i-1][j];
                }
                else {
                    obstacleGrid[i][j] = obstacleGrid[i - 1][j] + obstacleGrid[i][j - 1];
                }
            }
        }
        return obstacleGrid[obstacleGrid.length - 1][obstacleGrid[0].length - 1];
    }
}

64. Minimum Path Sum

Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.

Note: You can only move either down or right at any point in time.

Example:
Input:
[
  [1,3,1],
  [1,5,1],
  [4,2,1]
]
Output: 7
Explanation: Because the path 1→3→1→1→1 minimizes the sum.

class Solution {
    public int minPathSum(int[][] grid) {
        //貪心法,從尾到頭依次計算每個節點到結尾的minPathSum
        int[][] minSum = new int[grid.length][grid[0].length];
        int i = grid.length - 1;
        int j = grid[0].length - 1;
        minSum[i][j] = grid[i][j];
        //先計算兩個邊界的minPathSum
        while(--i >= 0)
            minSum[i][j] = grid[i][j] + minSum[i + 1][j];
        i = grid.length - 1;
        while(--j >= 0)
            minSum[i][j] = grid[i][j] + minSum[i][j + 1];
        //雙重循環,計算每個節點到結尾的minPathSum
        for(i = grid.length - 2; i >= 0; i--) {
            for(j = grid[0].length - 2; j >= 0; j--) {
                minSum[i][j] = grid[i][j] + Math.min(minSum[i + 1][j], minSum[i][j + 1]);
            }
        }
        return minSum[0][0];
    }
}

75. Sort Colors

Given an array with n objects colored red, white or blue, sort them in-place so that objects of the same color are adjacent, with the colors in the order red, white and blue.

Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively.

Note: You are not suppose to use the library's sort function for this problem.

Example:
Input: [2,0,2,1,1,0]
Output: [0,0,1,1,2,2]

Follow up:
A rather straight forward solution is a two-pass algorithm using counting sort.
First, iterate the array counting number of 0's, 1's, and 2's, then overwrite array with total number of 0's, then 1's and followed by 2's.
Could you come up with a one-pass algorithm using only constant space?

class Solution {
    public void sortColors(int[] nums) {
        int p1 = 0, p2 = nums.length - 1;
        int i = 0;
        while(i <= p2) {
            if(nums[i] == 0) {  //所有0移到前面, nums[p1]是遍歷過的,所以i不需要靜止
                nums[i] = nums[p1];
                nums[p1] = 0;
                p1++;
            }
            if(nums[i] == 2) {  //所有2移到後面
                nums[i] = nums[p2];
                nums[p2] = 2;
                p2--;
                i--;  //i要靜止檢查新的nums[i]
            }
            i++;
        }
    }
}

78. Subsets

Given a set of distinct integers, nums, return all possible subsets (the power set).

Note: The solution set must not contain duplicate subsets.

Example:

Input: nums = [1,2,3]
Output:
[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        result.add(new ArrayList<Integer>());
        
        for(int i = 0; i < nums.length; i++) {  //逐個加入新元素
            addToSubsets(result, nums[i]);
        }
        return result;
    }
    
    public void addToSubsets(List<List<Integer>> result, int number) {
        int size = result.size();  //先保存size
        //在原來的基礎上每個list都add新元素,就構成要添加的所有list
        for(int j = 0; j < size; j++) {
            List<Integer> list = new ArrayList<Integer>();
            list.addAll(result.get(j));
            list.add(number);
            result.add(list);
        }
    }
}

79. Word Search

Given a 2D board and a word, find if the word exists in the grid.

The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once.

Example:

board =
[
  ['A','B','C','E'],
  ['S','F','C','S'],
  ['A','D','E','E']
]

Given word = "ABCCED", return true.
Given word = "SEE", return true.
Given word = "ABCB", return false.

class Solution {
    public boolean exist(char[][] board, String word) {
        for(int i = 0; i < board.length; i++) {
            for(int j = 0; j < board[i].length; j++) {
                if(exist(board, i, j, word.toCharArray(), 0))
                    return true;
            }
        }
        return false;
    }
    //簡單回溯算法
    private boolean exist(char[][] board, int i, int j, char[] word, int count) {
        if(count == word.length)
            return true;
        if(i < 0 || j < 0 || i == board.length || j == board[i].length)
            return false;
        if(board[i][j] != word[count])
            return false;
        board[i][j] ^= 256;  //mask the first correct letter, 再經過時一定不等於word中字母
        boolean result = 
            exist(board, i + 1, j, word, count + 1) || 
            exist(board, i - 1, j, word, count + 1) ||
            exist(board, i, j + 1, word, count + 1) ||
            exist(board, i, j - 1, word, count + 1);
        board[i][j] ^= 256;  //解開mask
        return result;
    }
}

81. Search in Rotated Sorted Array II

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.

(i.e., [0,0,1,2,2,5,6] might become [2,5,6,0,0,1,2]).

You are given a target value to search. If found in the array return true, otherwise return false.


Example 1:
Input: nums = [2,5,6,0,0,1,2], target = 0
Output: true

Example 2:
Input: nums = [2,5,6,0,0,1,2], target = 3
Output: false

class Solution {
    public boolean search(int[] nums, int target) {
        return binarySearch(nums, target, 0, nums.length - 1);
    }
    //二分查找
    public boolean binarySearch(int[] nums, int target, int start, int end) {
        while(start <= end) {
            int mid = (start + end) / 2;
            if(target == nums[mid])
                return true;
            if(nums[mid] > nums[start]) {  //說明左半邊包括mid是升序
                if(target >= nums[start] && target < nums[mid])  //target在左半邊
                    end = mid - 1;
                else  //否則在左半邊
                    start = mid + 1;
            }
            else if(nums[mid] < nums[end]){  //說明右半邊包括mid是升序
                if(target > nums[mid] && target <= nums[end])  //target在右半邊
                    start = mid + 1;
                else  //否則在右半邊
                    end = mid - 1;
            }
            else  //不清楚順序,直接兩邊都判斷
                return binarySearch(nums, target, start, mid - 1) || binarySearch(nums, target, mid + 1, end);
        }
        return false;
    }
}

94. Binary Tree Inorder Traversal

Given a binary tree, return the inorder traversal of its nodes' values.

Example:

Input: [1,null,2,3]
   1
    \
     2
    /
   3

Output: [1,3,2]

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<Integer>();
        inorder(root, result);
        return result;
    }
    //簡單中序遍歷
    public void inorder(TreeNode root, List<Integer> result) {
        if(root == null)
            return;
        inorder(root.left, result);
        result.add(root.val);
        inorder(root.right, result);
    }
}

95. 不同的二叉搜索樹 II

給定一個整數 n,生成所有由 1 ... n 爲節點所組成的二叉搜索樹

輸入: 3
輸出:
[
  [1,null,3,2],
  [3,2,null,1],
  [3,1,null,null,2],
  [2,1,3],
  [1,null,2,null,3]
]
解釋:
以上的輸出對應以下 5 種不同結構的二叉搜索樹:

   1           3       3      2      1
     \         /        /        /  \       \
      3     2      1       1    3      2
     /      /           \                       \
  2      1             2                     3

class Solution {
    public List<TreeNode> generateTrees(int n) {
        return generateTrees(1, n);
    }
    public List<TreeNode> generateTrees(int start, int end) {
        //遞歸得到子樹的List,再逐個遍歷組裝成當前層次的新樹
        List<TreeNode> res = new ArrayList<TreeNode>();
        if(start == end) {  //遞歸出口,單個節點
            res.add(new TreeNode(start));
            return res;
        }
        else if(start > end)
            return res;
        //下面是start < end 的情況
        List<TreeNode> leftRes;  //左子樹List
        List<TreeNode> rightRes;  //右子樹List
        
        rightRes = generateTrees(start + 1, end);  //處理左端點
        for(TreeNode right : rightRes) {
            TreeNode root = new TreeNode(start);
            root.right = right;
            res.add(root);
        }
        
        for(int i = start + 1; i < end; i++) {  //每個元素都可以作爲根節點,兩個端點時特殊處理
            leftRes = generateTrees(start, i - 1);
            rightRes = generateTrees(i + 1, end);
            for(TreeNode left : leftRes) {
                for(TreeNode right : rightRes) {
                    TreeNode root = new TreeNode(i);
                    root.left = left;
                    root.right = right;
                    res.add(root);
                }
            }
        }
        
        leftRes = generateTrees(start, end - 1);  //處理右端點
        for(TreeNode left : leftRes) {
            TreeNode root = new TreeNode(end);
            root.left = left;
            res.add(root);
        }
        
        return res;
    }
}

96. Unique Binary Search Trees

Given n, how many structurally unique BST's (binary search trees) that store values 1 ... n?

Example:
Input: 3
Output: 5
Explanation:
Given n = 3, there are a total of 5  unique BST's:

   1           3      3       2     1
     \         /       /         / \       \
      3     2      1       1   3      2
     /      /          \                       \
   2     1            2                      3

class Solution {
    public int numTrees(int n) {
        if(n <= 2)
            return n;
        //用數組不用遞歸,可以更快
        int[] nums = new int[n + 1];  //爲了更容易理解nums[0]不放數據
        nums[1] = 1;
        nums[2] = 2;
        for(int i = 3; i <= n; i++) {
            function(i, nums);
        }    
        return nums[n];
    }
    public void function(int n, int[] nums) {
        nums[n] = 0;
        nums[n] += nums[n - 1] * 2;  //左右子數分別爲空時
        for(int i = 1; i < n / 2; i++) {  //左子樹i個節點,右子樹n-1-i個
            nums[n] += nums[i] * nums[n - 1 - i] * 2;
        }
        if(n % 2 == 1)  //n爲奇數時,加上左右都爲n/2個的情況
            nums[n] += Math.pow(nums[n / 2], 2);
    }
}

98. Validate Binary Search Tree

Given a binary tree, determine if it is a valid binary search tree (BST).

Assume a BST is defined as follows:

  • The left subtree of a node contains only nodes with keys less thanthe node's key.
  • The right subtree of a node contains only nodes with keys greater than the node's key.
  • Both the left and right subtrees must also be binary search trees.

Example 1:
    2
    / \
  1   3
Input: [2,1,3]
Output: true

Example 2:
    5
    / \
  1   4
       / \
     3   6
Input: [5,1,4,null,null,3,6]
Output: false
Explanation: The root node's value is 5 but its right child's value is 4.

class Solution {
    public boolean isValidBST(TreeNode root) {
        return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE);
    }
    public boolean isValidBST(TreeNode root, long min, long max) {
        if(root == null)
            return true;
        //必須要 min < root.val < max
        if(root.val >= max || root.val <= min)
            return false;
        //遞歸縮小範圍
        return isValidBST(root.left, min, root.val) && isValidBST(root.right, root.val, max);
    }
}

101. Symmetric Tree

Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).

For example, this binary tree [1,2,2,3,4,4,3] is symmetric:

      1
      / \
   2    2
  / \     / \
3  4  4  3
 

But the following [1,2,2,null,3,null,3] is not:

    1
    / \
  2   2
    \     \
    3     3

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if(root == null) 
            return true;
        else return mirror(root.left, root.right);
    }
    //判斷兩個樹互爲鏡像
    public boolean mirror(TreeNode a, TreeNode b) {
        if(a == null && b == null)
            return true;
        if(a != null && b != null){
            if(a.val != b.val)
                return false;
            else 
                return mirror(a.left, b.right) && mirror(a.right, b.left);
        }
        else
            return false;
    }
}

102. Binary Tree Level Order Traversal

Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level).

For example:
Given binary tree [3,9,20,null,null,15,7],

    3
    / \
  9  20
      /  \
   15   7
return its level order traversal as:
[
  [3],
  [9,20],
  [15,7]
]

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new LinkedList<List<Integer>>();
        if(root == null)
            return res;
        
        preOrder(root, 0, res);
        return res;
    }
    //帶深度參數的前序遍歷即可
    public void preOrder(TreeNode root, int depth, List<List<Integer>> res) {
        if(root != null) {
            if(depth + 1 > res.size()){
                List<Integer> list = new LinkedList<Integer>();
                list.add(root.val);
                res.add(list);
            }
            else{
                List<Integer> list = res.get(depth);
                list.add(root.val);
            }
            preOrder(root.left, depth + 1, res);
            preOrder(root.right, depth + 1, res);
        }
    }
}

104. Maximum Depth of Binary Tree

Given a binary tree, find its maximum depth.

The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.

Note: A leaf is a node with no children.

Example:
Given binary tree [3,9,20,null,null,15,7],

    3
    / \
  9  20
       /  \
    15   7
return its depth = 3.

class Solution {
    public int maxDepth(TreeNode root) {
        if(root == null) return 0;
        else return Math.max(maxDepth(root.left) + 1, maxDepth(root.right) + 1);
    }
}

105. Construct Binary Tree from Preorder and Inorder Traversal

Given preorder and inorder traversal of a tree, construct the binary tree.

Note:
You may assume that duplicates do not exist in the tree.

For example, given

preorder = [3,9,20,15,7]
inorder = [9,3,15,20,7]
Return the following binary tree:

    3
    / \
  9  20
      /  \
   15   7

public class Solution {
    //劍指offer中做過,copy過來
    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
        return reConstructBinaryTree(pre, 0, pre.length - 1, in, 0, in.length - 1);
    }
    //用下標獲取每個子樹的前序和中序序列
    public TreeNode reConstructBinaryTree(int [] pre, int preStart, int preEnd, 
                                          int [] in, int inStart, int inEnd) {
        if(preStart > preEnd || inStart > inEnd)  //序列爲空,返回null
            return null;
        TreeNode res = new TreeNode(pre[preStart]);  //前序第1個值是根節點
        if(preStart == preEnd)  //只有一個節點
            return res;
        int leftCount = 0;  //左子樹的大小
        for(int i = inStart; in[i] != pre[preStart]; i++)
            leftCount++;
        res.left = reConstructBinaryTree(pre, preStart + 1, preStart + leftCount,
                                         in, inStart, inStart + leftCount - 1);
        res.right = reConstructBinaryTree(pre, preStart + leftCount + 1, preEnd,
                                          in, inStart + leftCount + 1, inEnd);
        return res;
    }
}

114. Flatten Binary Tree to Linked List

Given a binary tree, flatten it to a linked list in-place.

For example, given the following tree:

    1
    / \
  2   5
  / \     \
3   4    6
The flattened tree should look like:

1
  \
   2
     \
      3
        \
         4
           \
            5
              \
               6

class Solution {
    public void flatten(TreeNode root) {
        if(root == null) 
            return;
        TreeNode left = root.left;
        TreeNode right = root.right;
        root.left = null;
        flatten(left);
        root.right = left;
        while(root.right != null)  //遍歷至最右
            root = root.right;
        flatten(right);
        root.right = right;
        return;
    }
}

121. Best Time to Buy and Sell Stock

Say you have an array for which the ith element is the price of a given stock on day i.

If you were only permitted to complete at most one transaction (i.e., buy one and sell one share of the stock), design an algorithm to find the maximum profit.

Note that you cannot sell a stock before you buy one.

Example 1:
Input: [7,1,5,3,6,4]
Output: 5
Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5.
             Not 7-1 = 6, as selling price needs to be larger than buying price.

Example 2:
Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.

class Solution {
    public int maxProfit(int[] prices) {
        if(prices.length == 0)
            return 0;
        int buy = prices[0];
        int max = 0;
        for(int i = 1; i < prices.length; i++) {
            if(prices[i] < buy)  //更改買入時間
                buy = prices[i];
            else {
                max = Math.max(max, prices[i] - buy);
            }
        }
        return max;
    }
}

128. 最長連續序列

給定一個未排序的整數數組,找出最長連續序列的長度。

要求算法的時間複雜度爲 O(n)

示例:

輸入: [100, 4, 200, 1, 3, 2]
輸出: 4
解釋: 最長連續序列是 [1, 2, 3, 4]。它的長度爲 4。

class Solution {
    public int longestConsecutive(int[] nums) {
        Set<Integer> set = new HashSet<Integer>();
        for(Integer num : nums) {
            set.add(num);
        }
        int maxlen = 0;
        //對每個元素搜索set中與其相鄰的所有元素,並移除
        //(相當於一次移除了一整個連續子序列)
        for(Integer num : nums) {
            //如果set中有當前元素
            if(set.remove(num)) {
                int curlen = 1;
                int cur = num;
                //當前元素向左搜索
                while(set.remove(cur - 1)) {  
                    cur--;
                }
                curlen += num - cur;
                cur = num;
                //當前元素向右搜索
                while(set.remove(cur + 1)) {  
                    cur++;
                }
                curlen += cur - num;
                //更新maxlen
                maxlen = Math.max(maxlen, curlen);
            }
        }
        return maxlen;
    }
}

129. 求根到葉子節點數字之和

給定一個二叉樹,它的每個結點都存放一個 0-9 的數字,每條從根到葉子節點的路徑都代表一個數字。

例如,從根到葉子節點路徑 1->2->3 代表數字 123。

計算從根到葉子節點生成的所有數字之和。

說明: 葉子節點是指沒有子節點的節點。

示例 1:
輸入: [1,2,3]
    1
   / \
  2   3
輸出: 25
解釋:
從根到葉子節點路徑 1->2 代表數字 12.
從根到葉子節點路徑 1->3 代表數字 13.
因此,數字總和 = 12 + 13 = 25.

示例 2:
輸入: [4,9,0,5,1]
    4
   / \
  9   0
 / \
5   1
輸出: 1026
解釋:
從根到葉子節點路徑 4->9->5 代表數字 495.
從根到葉子節點路徑 4->9->1 代表數字 491.
從根到葉子節點路徑 4->0 代表數字 40.
因此,數字總和 = 495 + 491 + 40 = 1026.

class Solution {
    public int sumNumbers(TreeNode root) {
        if(root == null) {
            return 0;
        }
        int[] sum = new int[1];
        int cur = 0;
        preOrder(root, cur, sum);
        return sum[0];
    }
    //前序遍歷,因爲子樹需要當前val對cur的更新
    //每到葉子節點就加到sum裏
    public void preOrder(TreeNode root, int cur, int[] sum) {
        if(root == null) {
            return;
        }
        //更新cur
        cur = cur * 10 + root.val;
        //葉子節點,加入sum
        if(root.left == null && root.right == null) {
            sum[0] += cur;
            return;
        }
        preOrder(root.left, cur, sum);
        preOrder(root.right, cur, sum);
    }
}

136. Single Number

Given a non-empty array of integers, every element appears twice except for one. Find that single one.

Note:

Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

Example 1:
Input: [2,2,1]
Output: 1

Example 2:
Input: [4,1,2,1,2]
Output: 4

class Solution {
    //劍指offer做過,遍歷一次位運算異或即可
    public int singleNumber(int[] nums) {
        int x = 0;
        for(int i = 0; i < nums.length; i++){
            x ^= nums[i];
        }
        return x;
    }
}

138. 複製帶隨機指針的鏈表

給定一個鏈表,每個節點包含一個額外增加的隨機指針,該指針可以指向鏈表中的任何節點或空節點。

要求返回這個鏈表的深拷貝。 

/*
class Node {
    public int val;
    public Node next;
    public Node random;

    public Node() {}

    public Node(int _val,Node _next,Node _random) {
        val = _val;
        next = _next;
        random = _random;
    }
};
*/
class Solution {
    //採用逐點複製插入原鏈表相應節點之後的方法,可以不需要額外空間
    public Node copyRandomList(Node head) {
        if(head == null) {
            return null;
        }
        //頭節點非空,先複製頭節點爲res
        Node res = new Node(head.val, null, null);
        res.next = head.next;
        head.next = res;
        //第一輪複製,先不考慮隨機指針,每個複製的節點插入到原節點之後
        for(Node p = res.next; p != null;) {
            Node p1 = new Node(p.val, null, null);
            p1.next = p.next;
            p.next = p1;
            p = p1.next;
        }
        //第二輪,連接隨機指針,p1.random = p.random.next;
        for(Node p = head; p != null;) {
            Node p1 = p.next;
            if(p.random != null) {
                p1.random = p.random.next;
            }
            p = p1.next;
        }
        //最後取出複製的鏈表,並將原鏈表還原
        head.next = res.next;
        for(Node p = res.next, p1 = res; p != null;) {
            p1.next = p.next;
            p1 = p1.next;
            p.next = p1.next;
            p = p.next;
        }
        return res;
    }
}

139. Word Break

Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be segmented into a space-separated sequence of one or more dictionary words.

Note:

  • The same word in the dictionary may be reused multiple times in the segmentation.
  • You may assume the dictionary does not contain duplicate words

Example 1:
Input: s = "leetcode", wordDict = ["leet", "code"]
Output: true
Explanation: Return true because "leetcode" can be segmented as "leet code".

Example 2:
Input: s = "applepenapple", wordDict = ["apple", "pen"]
Output: true
Explanation: Return true because "applepenapple" can be segmented as "apple pen apple".
             Note that you are allowed to reuse a dictionary word.

class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        Set<Integer> invalidCutIndex = new HashSet<Integer>();  //記錄無效切點
        return dfs(s, 0, wordDict, invalidCutIndex);
    }
    //dfs只關心從切點i開始到結尾這部分是否能夠成功切分
    public boolean dfs(String s, int i, List<String> wordDict, Set<Integer> invalidCutIndex) {
        if(i == s.length())
            return true;
        if(invalidCutIndex.contains(i))
            return false;
        for(int cutIndex = i + 1; cutIndex < s.length() + 1; cutIndex++) {  //切點處被切分到右半段
            if(wordDict.contains(s.substring(i, cutIndex))) {  //首先左半邊要存在於單詞表中
                if(dfs(s, cutIndex, wordDict, invalidCutIndex))
                    return true;
                else
                    invalidCutIndex.add(cutIndex);  //無效的cutIndex
            }
        }
        invalidCutIndex.add(i);  //無效的切點i
        return false;
    }
}

141. Linked List Cycle

Given a linked list, determine if it has a cycle in it.

To represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to. If pos is -1, then there is no cycle in the linked list.

Example 1:

Input: head = [3,2,0,-4], pos = 1
Output: true
Explanation: There is a cycle in the linked list, where tail connects to the second node.

Example 2:

Input: head = [1,2], pos = 0
Output: true
Explanation: There is a cycle in the linked list, where tail connects to the first node.

Example 3:

Input: head = [1], pos = -1
Output: false
Explanation: There is no cycle in the linked list.

public class Solution {
    public boolean hasCycle(ListNode head) {
        if(head == null || head.next == null)  //注意節點數小於兩個的情況
            return false;
        ListNode slow = head, fast = head.next;  //初始值不相等
        while(fast != null && slow != fast) {
            if(fast.next == null)
                break;
            fast = fast.next.next;
            slow = slow.next;
        }
        if(slow == fast)
            return true;
        else
            return false;
    }
}

142. Linked List Cycle II

Given a linked list, return the node where the cycle begins. If there is no cycle, return null.

To represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to. If pos is -1, then there is no cycle in the linked list.

Note: Do not modify the linked list.

Example 1:

Input: head = [3,2,0,-4], pos = 1
Output: tail connects to node index 1
Explanation: There is a cycle in the linked list, where tail connects to the second node.

Example 2:

Input: head = [1,2], pos = 0
Output: tail connects to node index 0
Explanation: There is a cycle in the linked list, where tail connects to the first node.

Example 3:

Input: head = [1], pos = -1
Output: no cycle
Explanation: There is no cycle in the linked list.

public class Solution {
    //劍指offer做過
    public ListNode EntryNodeOfLoop(ListNode pHead) {
        if(pHead == null)
            return null;
        else if(pHead.next == null)
            return null;
        ListNode fast = pHead, slow = pHead, start = pHead;
        while(fast != null) {
            if(fast.next != null)
                fast = fast.next.next;
            else
                fast = fast.next;  //此時fast已經爲null
            slow = slow.next;
            if(fast == slow) {  //相等處fast多走了整數個環長,也是slow走的長度
                while(start != slow) {  //再走1個環外長度就剛好會遇到
                    start = start.next;
                    slow = slow.next;
                }
                break;
            }
        }
        if(fast == null)  //無環
            return null;
        else
            return start;
    }
}

148. Sort List

Sort a linked list in O(n log n) time using constant space complexity.

Example 1:
Input: 4->2->1->3
Output: 1->2->3->4

Example 2:
Input: -1->5->3->4->0
Output: -1->0->3->4->5

class Solution {
    public ListNode sortList(ListNode head) {
        if(head == null || head.next == null)
            return head;
        // 1.分成兩半
        ListNode prev = null, slow = head, fast = head;
        while(fast != null && fast.next != null) {
            prev = slow;
            slow = slow.next;
            fast = fast.next.next;
        }
        prev.next = null;
        // 2.分別排序
        ListNode l1 = sortList(head);
        ListNode l2 = sortList(slow);
        // 3.合併l1和l2
        return merge(l1, l2);
    }
    //合併兩個升序鏈表
    ListNode merge(ListNode l1, ListNode l2) {
        ListNode l = new ListNode(0), p = l;
        while(l1 != null && l2 != null) {
            if (l1.val < l2.val) {
                p.next = l1;
                l1 = l1.next;
            }
            else {
                p.next = l2;
                l2 = l2.next;
            }
            p = p.next;
        }
        if(l1 != null)
            p.next = l1;
        else
            p.next = l2;
        return l.next;
    }
}

152. Maximum Product Subarray

Given an integer array nums, find the contiguous subarray within an array (containing at least one number) which has the largest product.

Example 1:
Input: [2,3,-2,4]
Output: 6
Explanation: [2,3] has the largest product 6.

Example 2:
Input: [-2,0,-1]
Output: 0
Explanation: The result cannot be 2, because [-2,-1] is not a subarray.

class Solution {
    public int maxProduct(int[] nums) {
        int max = nums[0];
        int curMax = nums[0], curMin = nums[0];
        
        //每一位都計算包含當位數字的乘積最大值和最小值纔行(負數使最大最小顛倒)
        for(int i = 1; i < nums.length; i++) {  
            if(nums[i] < 0) {
                int temp = curMax;
                curMax = curMin;
                curMin = temp;
            }
            
            curMax = Math.max(nums[i], nums[i] * curMax);
            curMin = Math.min(nums[i], nums[i] * curMin);
            max = Math.max(max, curMax);
        }
        return max;
    }
}

169. Majority Element

Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.

You may assume that the array is non-empty and the majority element always exist in the array.

Example 1:
Input: [3,2,3]
Output: 3

Example 2:
Input: [2,2,1,1,1,2,2]
Output: 2

class Solution {
    public int majorityElement(int[] nums) {
        int major = nums[0];
        int count = 1;
        //major元素多於一半,因此總會把count置爲正
        for(int i = 1; i < nums.length; i++) {  
            if(count == 0) {  //換新元素
                major = nums[i];
                count = 1;
            }
            else if(major == nums[i])
                count++;
            else
                count--;
        }
        return major;
    }
}

198. House Robber

You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.

Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

Example 1:
Input: [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
             Total amount you can rob = 1 + 3 = 4.

Example 2:
Input: [2,7,9,3,1]
Output: 12
Explanation: Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5 (money = 1).
             Total amount you can rob = 2 + 9 + 1 = 12.

class Solution {
    public int rob(int[] nums) {
        //分別爲是否包含當前元素的最大和
        int sumNotContain = 0, sumContain = 0;
        for(int i = 0; i < nums.length; i++) {
            int temp = sumNotContain;
            sumNotContain = Math.max(sumNotContain, sumContain);  //此時sumContain仍是包含上一個元素
            sumContain = nums[i] + temp;
        }
        return Math.max(sumNotContain, sumContain);
    }
}

200. 島嶼數量

給定一個由 '1'(陸地)和 '0'(水)組成的的二維網格,計算島嶼的數量。一個島被水包圍,並且它是通過水平方向或垂直方向上相鄰的陸地連接而成的。你可以假設網格的四個邊均被水包圍。

示例 1:
輸入:
11110
11010
11000
00000

輸出: 1

示例 2:
輸入:
11000
11000
00100
00011

輸出: 3

class Solution {
    public int numIslands(char[][] grid) {
        int count = 0;
        for(int i = 0; i < grid.length; i++) {
            for(int j = 0; j < grid[i].length; j++) {
                //每發現一個island就dfsFill把整個island消除
                if(grid[i][j] == '1') {
                    count++;
                    dfsFill(grid, i, j);
                }
            }
        }
        return count;
    }
    public void dfsFill(char[][] grid, int i, int j) {
        //return在前減少計算次數
        if(i < 0 || i >= grid.length || j < 0 || j >= grid[i].length || grid[i][j] == '0') 
            return;
        grid[i][j] = '0';
        dfsFill(grid, i - 1, j);
        dfsFill(grid, i + 1, j);
        dfsFill(grid, i, j - 1);
        dfsFill(grid, i, j + 1);
    }
}

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章