刷题记录之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);
    }
}

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值