LeetCode面試常見100題( TOP 100 Liked Questions)

這篇文章是關於LeetCode Top 100 Liked Questions 的 專欄記錄,其中部分題目可能包括解題思路和多種優化解法。我把自己的思路都記錄在這裏,如果你看見了,請記得點個贊吧,蟹蟹【手動笑臉】。


目錄


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].

/**
     * 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].
     * @param nums
     * @param target
     * @return
     */
    public static int[] twoSum(int[] nums, int target) {
        int[] result= new int[2];
        if(nums.length>1){
            for(int i=0;i<nums.length;i++){
                for(int j=i+1;j<nums.length;j++){
                    if(nums[i]+nums[j]==target){
                        result[0]=i;
                        result[1]=j;
                    }
                }
            }

        }
        return result;
    }

2、Add Two Numbers

Description:
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.
/**
     * Description: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.
     * @param l1
     * @param l2
     * @return
     */
    public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode result = new ListNode(0);  //創建頭結點
        ListNode phead = result;
        int flag =0;    //進位
        while(l1!=null && l2!=null ){//連個鏈表都不爲空
            int val = l1.val + l2.val + flag;
            flag = 0;
            if(val>9){
                flag =1;
                val = val % 10;
            }
            //創建鏈表節點並添加到head尾
            ListNode temp = new ListNode(val);
            phead.next=temp;
            l1 = l1.next;
            l2 = l2.next;
            phead = phead.next;
        }
        if(l1 == null){//如果l1已經遍歷完成,而l2還不爲空
            while(l2!=null){
                int val = l2.val + flag;
                flag =0;
                if(val >9){
                    flag =1;
                    val = val % 10;
                }
                ListNode temp = new ListNode(val);
                phead.next = temp;
                l2 = l2.next;
                phead = phead.next;
            }       
        }
        if(l2 == null){
            while(l1 !=null){
                int val = l1.val + flag;
                flag =0;
                if(val >9){
                    flag =1;
                    val = val % 10;
                }
                ListNode temp = new ListNode(val);
                phead.next = temp;
                l1 = l1.next;
                phead = phead.next;
            }
        }
        if(flag ==1){
            ListNode temp = new ListNode(1);
            phead.next = temp;
        }
        return result.next;
    }

優化解法:

/**
     * 解法二:
     * @param l1
     * @param l2
     * @return
     */
    public ListNode addTwoNumbers2(ListNode l1, ListNode l2) {
        ListNode dummyHead = new ListNode(0);
        ListNode p = l1, q = l2, curr = dummyHead;
        int carry = 0;
        while (p != null || q != null) {
            int x = (p != null) ? p.val : 0;
            int y = (q != null) ? q.val : 0;
            int sum = carry + x + y;
            carry = sum / 10;
            curr.next = new ListNode(sum % 10);
            curr = curr.next;
            if (p != null) p = p.next;
            if (q != null) q = q.next;
        }
        if (carry > 0) {
            curr.next = new ListNode(carry);
        }
        return dummyHead.next;
    }

3、Longest Substring Without Repeating Characters

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

Examples:

Given "abcabcbb", the answer is "abc", which the length is 3.

Given "bbbbb", the answer is "b", with the length of 1.

Given "pwwkew", 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.

/**
     * 題目描述:
     * Given a string, find the length of the longest substring without repeating
     * characters.
     * Examples:
     *          Given "abcabcbb", the answer is "abc", which the length is 3.
     *          Given "bbbbb", the answer is "b", with the length of 1.
     *          Given "pwwkew", 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.
     * 解題思路:
     * 利用滑動窗口[i,j)表示從位置i到j的子字符串str,用集合Set表示str中的字符集合,用maxL表示該字符串
     * 長度,進行以下操作:
     * 1)先滑動窗口的右部邊界,即j+1,判斷str中是否出現重複字符:
     *          若果未出現,則更新Set和maxL,並繼續1)步驟
     *          如果出現重複步驟,則表示當前子串已不能再擴大長度,故執行2)步驟
     * 2)滑動窗口的左部邊界,接i+1,同時判斷str中是否包含重複字符
     * @param s
     */
    public int lengthOfLongestSubstring(String s) {

            int maxL = 0;   //記錄最大子串的長度
            Set<Character> charSet = new HashSet<Character>();
            int i=0,j=0;    //滑動窗口的起點和終點
            while(i<s.length() && j<s.length()){

                if(!charSet.contains(s.charAt(j))){
                    charSet.add(s.charAt(j));
                    maxL = Math.max(maxL,j-i+1);
                    j++;
                }else{
                    charSet.remove(s.charAt(i));
                    i++;    
                }

            }
            return maxL;     

    }
/**
     * 優化解法:
     * 思路:
     * 實際上根據以上思路我們可以得出更加優化的解法:
     * 我們可以用hashmap存儲字符串的字符與索引之間的對應關係,這樣當滑動窗口檢[i,j)測出重複字符時:
     * 我們只需要找到該字符在hashmap中的索引,假定爲j',那麼我們只需要將i置爲j'+1,並重新開始找就可以了
     * @param args
     */
    public static int lengthOfLongestSubstring2(String s) {

        int maxL = 0;   //記錄最大子串的長度
        Map<Character,Integer> hashmap = new HashMap<Character,Integer>();
        int i=0,j=0;    //滑動窗口的起點和終點
        while(i<s.length() && j<s.length()){

            if(!hashmap.containsKey(s.charAt(j))){
                hashmap.put(s.charAt(j), j);
                maxL = Math.max(maxL,j-i+1);
                j++;
            }else{
                int index = hashmap.get(s.charAt(j));  //獲取重複字符的索引
                for(int k=i;k<=index;k++){
                    hashmap.remove(s.charAt(k));
                }
                i = index +1;   
            }
        }
        return maxL;
    }

4. Median of Two Sorted Arrays

Description:
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
/**
     * 4. Median of Two Sorted Arrays
     * Description:
     * 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)).
     * 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
     *************************************************************************
     * 思路:
     * 我們將兩個有序數組分別用A[:m-1]、B[:n-1]來表示。
     * 假定我們用A[:i-1]、A[i:m-1]將數組A切分;用B[:j-1]、B[j:n-1]將數組B切分;則只要保證以下條件:
     * 1)i+j = m-i + n-j;(此時,i=0~m,j=(m+n+1)/2 -i);注意爲了保證j非負,這裏n>=m
     * 2)B[j-1] <= A[i],A[i-1] <= B[j]
     * 那麼我們就可以計算出:
     *      median = (max(left_part) + min(right_part))/2
     * 綜合以上思路,解題的關鍵就是尋找合適的i和j,這裏我們擬採用“二分查找法”。步驟如下
     * 假定 imin=0,imax=m;則我們需要在[imin,imax]中尋找合適的i值,我們假設:
     * i = (imin + imax)/2,  j=(m+n+1)/2 - i,這樣我們可以保證len(left_part) = len(right_part)
     * 在以上假定之後,我們共有以下三種情況需要考慮:
     * 1) B[j-1]<= A[i] 且 A[i-1] <= B[j]: 此時 i剛好滿足情況
     * 2) B[j-1] > A[i]: 此時說明i值太小,需要增加i,這時我們需要置 imin = i+1
     * 3) A[i-1] > B[j]: 此時壽命i值過大,需要減小i,這時我們需要置 imax = i-1
     * 最終結果爲:
     * 1)如果 m+n 爲奇數,則 median = max(A[i-1],B[j-1])
     * 2)如果 m+n 爲偶數,則 median = (max(A[i-1],B[j-1]) + min(A[i],B[j]))/2
     * 
     ************************************************************************* 
     * @param args
     */

    public static double findMedianSortedArrays(int[] A, int[] B) {
        int m = A.length;
        int n = B.length;
        //判斷第一個條件,m<=n
        if(m > n){
            int[] temp = A;
            A = B;
            B = temp;
            m = A.length;
            n = B.length;
        }
        int imin =0, imax = m;
        int i=0,j=0;
        int maxleft =0, minright=0;
        if(m==0 && n==0){
            return 0;
        }else if(m==0 && n==1){ // 當其中一個爲空數組,另一個長度爲1
            return B[0];
        }else{
            while(imin <= imax){
                i = (imin+imax)/2;
                j = (m+n+1)/2 -i;
                if(i < m && B[j-1] > A[i])
                    imin = i +1;
                else if(i > 0 && A[i-1] > B[j])
                    imax = i -1;
                else{   //符合條件
                    if(i==0)
                        maxleft = B[j-1];
                    else if (j==0)
                        maxleft = A[i-1];
                    else 
                        maxleft = Math.max(A[i-1], B[j-1]);

                    if(i==m)
                        minright = B[j];
                    else if(j==n)
                        minright = A[i];
                    else 
                        minright = Math.min(B[j], A[i]);

                    break;

                }
            }
        }

        if( (m+n)%2 ==0){//爲偶數
            return (maxleft + minright)/2.0;
        }else
            return maxleft;
    }

5、Longest Palindromic Substring

Description:
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"
/**
     * 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"
     */

    /**解法一:暴力解法
     * @param s
     * @return
     */
    public static String longestPalindrome(String s) {

        int maxLength=0;
        String LongestStr="";
        int length = s.length();
        for(int i=0;i<length;i++){
            for(int j=length-1;j>=i;j--)
                if(isPalindrome(i,j,s)){
                    int subLen = j-i+1;
                    if(subLen>maxLength){
                        LongestStr = s.substring(i,j+1);
                        maxLength=subLen;
                    }
                }
        }

        return LongestStr;
    }
    /**
     * 判斷字符串是否爲迴文結構
     * @param startIndex
     * @param endIndex
     * @param s
     * @return
     */
    public static boolean isPalindrome(int startIndex,int endIndex,String s){
        int i=startIndex,j=endIndex;
        for(;j>=i;i++,j--){
            if(s.charAt(i)!=s.charAt(j))
                return false;
        }
        return true;
    }
/**
     * 5、 Longest Palindromic Substring
     * 優化解法二:動態規劃解法
     * 思路:
     * 利用dp[j][i]表示字符串區間[j,i]是否爲迴文串,則dp[i][j]
     * 即如果我們找到兩個相同的字符S[i]和S[j],在兩種情況下他們能構成迴文串:
     *      第一種:這兩個字符位置相鄰或者就是同一個字符 即:
     *          dp[j][i] = (S[i]==S[j]) && (i-j<2)
     *      第二種:這兩個字符所包含的中間字符串爲迴文串,這個時候我們只需要驗證:
     *          dp[j][i] = (S[i]==S[j]) && (dp[j+1][i-1] && i-j>1)
     * @param s
     * @return
     */
    public static String longestPalindrome2(String s){
        if(s.equals(""))
            return "";
        int n = s.length();
        int maxLength=0;
        String LongestStr = "";
        boolean[][] dp = new boolean[n][n];
        for(int i=0;i<n;i++){
            for(int j=0;j<=i;j++){
                /*if(s.charAt(i)==s.charAt(j) && i-j<2) //即i=j或者i=j+1
                    dp[j][i]=true;
                if(s.charAt(i)==s.charAt(j) && dp[j+1][i-1] && i-j>1)
                    dp[j][i]=true;*/
                //這行代碼太牛皮
                dp[j][i] =(s.charAt(i)==s.charAt(j)) && (i-j<2 || dp[j+1][i-1]);

                if(dp[j][i] && maxLength<i-j+1){
                    maxLength=i-j+1;
                    LongestStr = s.substring(j,i+1);
                }
            }
        }

        return LongestStr;
    }

11. Container With Most Water

Description:
Given n non-negative integers a1, a2, …, an , where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) 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.
Example:

Input: [1,8,6,2,5,4,8,3,7]
Output: 49
/**
     * 11. Container With Most Water
     *      Given n non-negative integers a1, a2, ..., an , where each represents a point at coordinate (i, ai).
     *      n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). 
     *      Find two lines, which together with x-axis forms a container, such that the container contains the most water.
     * @param height
     * @return
     */
    public static int maxArea(int[] height) {
        if(height.length<1 || height ==null)
            return 0;
        int maxArea =0;
        int minval=0,j=0;
        for(int i=0;i<height.length;i++){
            j=height.length;
            /*minval =Math.min(height[i],height[j]);
            if(minval*(j-i)>maxArea)
                maxArea = minval*(j-i);*/
            if(i>0 && height[i]<height[i-1])
                continue;
            while(i<j){
                //包含的數值變大時才計算
                if(j==height.length || (height[j]<height[j-1] && height[j]<height[i])){
                    minval = Math.min(height[i],height[j-1]);
                    if(minval*(j-1-i)>maxArea)
                        maxArea=minval*(j-1-i);
                }
                j--;    
            }
        }
        return maxArea;
    }
/**
     * 11. Container With Most Water
     * 優化解法二:
     * 我們用兩個指針分別指向數組height的兩端,我們首先比較height[i]和height[j]的大小
     * 如果      height[i]>height[j] 則我們保留height[i],height[j--]
     *      否則,我們保留height[j],將height[i++]
     * 這樣做是因爲,面積的大小是由更小的那個值來決定,保留更小的值,同時將更大值的指針向靠近方向移動,無論如何是得不到更大的值的
     * @param height
     * @return
     */
    public static int maxArea2(int[] height) {
        int start=0,end=height.length-1;
        int maxVal=0;   //存儲面積的最大值
        while(start<end){
            maxVal = Math.max(Math.min(height[start],height[end])*(end-start),maxVal);
            //接着移動指針
            if(height[start]<height[end])
                start++;
            else
                end--;
        }
        return maxVal;
    }

15. 3Sum

Description:
Given an array nums of n integers, are there elements a, b, c 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]
]
/**
     * 15. 3Sum
     * Given an array nums of n integers, are there elements a, b, c 
     * 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]]
     * @param nums
     * @return
     */
    /**
     * 傳統的暴力解法需要O(N_3)的時間複雜度,因此我們可以這樣優化算法:
     * 1、先用快排,將整個數組排序
     * 2、然後對於每一個排序後的元素,用兩個值的和等於某個定值的方法去解
     * @param nums
     * @return
     */
    public static List<List<Integer>> threeSum(int[] nums) {

        List<List<Integer>> result = new LinkedList<List<Integer>>();   //最終輸出結果
        if(nums == null || nums.length<3)
            return result;
        Arrays.sort(nums);   //java排序
        //排序後繼續檢查邊界
        if(nums[0]>0 || nums[nums.length-1]<0)
            return result;
        for(int i=0;i<nums.length-2;i++){
            if(i==0 || nums[i]!=nums[i-1]){
                int low = i+1,high = nums.length-1,sum = 0-nums[i];
                while(low<high){
                    if(nums[low]+nums[high]==sum){
                        result.add(Arrays.asList(nums[i],nums[low],nums[high]));
                        while(low<high && nums[low]==nums[low+1])
                            low++;
                        while(low<high && nums[high]==nums[high-1])
                            high--;
                        low++;high--;
                    }else if(nums[low]+nums[high]<sum)
                        low++;
                    else {
                        high--;
                    }
                }
            }
        }
        return result;
    }

16. 3Sum Closest

Description:
Given an array nums of n integers and an integer target, find three integers in nums such that the sum is closest to target. Return the sum of the three integers. You may assume that each input would have exactly one solution.
Example:

Given array nums = [-1, 2, 1, -4], and target = 1.
The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
/**
     * 16. 3Sum Closest
     * Given an array nums of n integers and an integer target, find three integers in nums 
     * such that the sum is closest to target. Return the sum of the three integers. 
     * You may assume that each input would have exactly one solution.
     * Example:
     * Given array nums = [-1, 2, 1, -4], and target = 1.
     * The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
     * @param nums
     * @param target
     * @return
     */
    public static int threeSumClosest(int[] nums, int target) {

        Arrays.sort(nums);
        int result = nums[0]+nums[1]+nums[nums.length-1];   //存儲最終結果
        for(int i=0;i<nums.length-2;i++){
            int low= i+1,high=nums.length-1;
            int temp = 0;
            while(low<high){
                temp=nums[i]+nums[low]+nums[high];
                if(temp>target)
                    high--;
                else if(temp<target)
                    low++;
                else{//相等  
                    return target;
                }
                if(Math.abs(temp-target)<Math.abs(result-target)){
                    result = temp;
                }
            }
        }
        return result;    
    }

17. Letter Combinations of a Phone Number

Description:
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.

/**
     * 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.
     * 方法一:遞歸方法
     * @param digits
     * @return
     */
    static String[] keyMapping ={"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
    public static List<String> letterCombinations(String digits) {

        List<String> result= new LinkedList<>();
        if(digits.equals(""))
            return result;
        combinationLetter("",digits,0,result);
        return result;     
    }
    /**
     * 遞歸拼接字符串
     * @param prefix 單個拼接的字符串
     * @param digits  輸入數字集
     * @param index 
     * @param result 結果列表
     */
    public static void combinationLetter(String prefix,String digits,int index,List<String> result){

        //遞歸結束條件
        if(index>=digits.length()){
            result.add(prefix);
            return;
        }
        //取出按鍵對應的字符串
        String letters = keyMapping[digits.charAt(index)-'0'];
        for(int i=0;i<letters.length();i++){
            combinationLetter(prefix+letters.charAt(i), digits, index+1, result);
        }
    }
/**
     * 方法二:使用隊列
     * @param digits
     * @return
     */
    public static List<String> letterCombinations2(String digits){

        List<String> result= new LinkedList<>();
        if(digits.equals(""))
            return result;
        Queue<String> strQueue = new LinkedList<>();
        String mapStr;
        strQueue.offer("");
        strQueue.offer("flag");
        for(int i=0;i<digits.length();i++){
            mapStr = keyMapping[digits.charAt(i)-'0'];      //取數字映射的字符串
            while(strQueue.peek()!="flag"){     //每組字符串添加完後都加一個標記
                for(int j=0;j<mapStr.length();j++){
                    String ch = mapStr.substring(j,j+1);
                    strQueue.offer(strQueue.peek()+ch);
                }
                strQueue.poll();
            }
            strQueue.offer("flag"); //在隊列末尾加標記位
            strQueue.poll();    //刪除隊列頭節點
        }
        //遍歷隊列
        while(!strQueue.isEmpty())
            result.add(strQueue.poll());
        result.remove(result.size()-1);
        return result;
    }
public static List<String> letterCombinations3(String digits){

        LinkedList<String> result= new LinkedList<>();
        if(digits.equals(""))
            return result;
        result.add("");
        while(result.peek().length() != digits.length()){   //注意終止條件通過隊列頭的字符串長度來判斷
            String first = result.poll();
            String mapStr = keyMapping[digits.charAt(first.length())-'0'];  //根據取出的隊列頭元素的長度來查找映射字典
            for(int i=0;i<mapStr.length();i++)
                result.offer(first+mapStr.charAt(i));
        }
        return result;
    }

19. Remove Nth Node From End of List

Description:
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?

/**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode(int x) { val = x; }
     * }
     */
    /**
     * 19. Remove Nth Node From End of List
     * Given a linked list, remove the n-th node from the end of list and return its head.
     * 思路:
     * 給定兩個指針first,second 我們只需要first先遍歷N個節點,讓後兩個一起開始遍歷,那麼當first到達尾部之後,second即爲倒數第N個節點
     * @param head
     * @param n
     * @return
     */
    public static ListNode removeNthFromEnd(ListNode head, int n) {

        ListNode first=head,preCur=head;
        int index=n+1;//需要記錄待刪除節點的父節點,所以加1
        //first指針先遍歷n+1個節點
        while(index-->0){
            first = first.next;
            if(first==null && index>0)  //index>0說明不存在待刪除節點的父節點,即刪除的就是頭節點
                return head.next;
        }
        //兩個指針一起遍歷
        while(first!=null){
            first=first.next;
            preCur=preCur.next;
        }
        preCur.next=preCur.next.next;
        return head;
    }

20. Valid Parentheses

Description:
Given a string containing just the characters ‘(‘, ‘)’, ‘{‘, ‘}’, ‘[’ and ‘]’, determine if the input string is valid.
An input string is valid if:
Open brackets must be closed by the same type of brackets.
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
 /**
     * 20. Valid Parentheses
     * Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.
     * An input string is valid if:
     * Open brackets must be closed by the same type of brackets.
     * Open brackets must be closed in the correct order.
     * Note that an empty string is also considered valid.
     * Example 1:
     * Input: "()"
     * Output: true
     * @param s
     * @return
     */
    public static boolean isValid(String s) {

        if(s==null || s.isEmpty())
            return true;
        //初始化一個棧
        Stack<Character> stack = new Stack<>();
        for(int i=0;i<s.length();i++){
            Character ch = s.charAt(i);
            if(!stack.isEmpty()){
                if((stack.peek()=='('&& ch==')') || (stack.peek()=='['&& ch==']') || (stack.peek()=='{'&& ch=='}')){
                    stack.pop();
                    continue;
                }
            }   
            stack.push(ch);
        }
        return stack.isEmpty();
    }

21. Merge Two Sorted Lists

Description:
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
/**
     * 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
     * @param l1
     * @param l2
     * @return
     */
    public static ListNode mergeTwoLists(ListNode l1, ListNode l2){
        ListNode p1=l1,p2=l2;
        ListNode phead = new ListNode(-1);  //創建頭結點
        ListNode index=phead;
        while(p1!=null && p2!=null){
            if(p1.val<=p2.val){
                index.next=p1;
                p1=p1.next;
                index=index.next;
            }else{
                index.next=p2;
                p2=p2.next;
                index=index.next;
            }
        }
        if(p1!=null)
            index.next=p1;
        if(p2!=null)
            index.next=p2;
        return phead.next;
    }
    public List<String> generateParenthesis(int n) {
        return generate("",n,0,0);

    }

22. Generate Parentheses

Description:
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:

[
  "((()))",
  "(()())",
  "(())()",
  "()(())",
  "()()()"
]
/**
     * 22. Generate Parentheses
     * Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
     * @param parenthese
     * @param num
     * @param left 左括號數
     * @param right 右括號數
     * @return
     */
    public static List<String> generate(String parenthese,int num,int left,int right){

        List<String> result = new ArrayList<String>();
        if(left < num){
            //生成的左括號數大於右括號數,則下一個括號可以爲左括號,也可以爲右括號
            if(left>right){
                result.addAll(generate(parenthese+"(",num,left+1,right));
                result.addAll(generate(parenthese+")",num,left,right+1));
            }
            else{   //左括號數和右括號數相同時,一定是添加左括號
                result.addAll(generate(parenthese+"(",num,left+1,right));
            }
        }
        if(left==num &&right<num){
            for(int i=right+1;i<=num;i++)
                parenthese += ")";
            right = num;
            result.add(parenthese);
        }
        return result;
    }

23. Merge k Sorted Lists

Description:
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
Example:

Input:
[
  1->4->5,
  1->3->4,
  2->6
]
Output: 1->1->2->3->4->4->5->6

解法一:

/**
     * 23. Merge k Sorted Lists
     * Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
     * Example:
     * Input:
     * [
     * 1->4->5,
     * 1->3->4,
     * 2->6
     * ]
     * Output: 1->1->2->3->4->4->5->6
     * Approach 2: Compare one by one
     * Time complexity : O(kN)where k is the number of linked lists.
     * @param lists
     * @return
     */
    public static ListNode mergeKLists(ListNode[] lists){
        if(lists==null || lists.length<1)
            return null;
        ListNode head = new ListNode(-1);
        ListNode phead =head;
        int count=0,index=0,min;    //奇數已經遍歷完的鏈表
        while(count<lists.length){
            //找出K個鏈表的頭結點值最小的那一個
            count=0;
            min = Integer.MAX_VALUE;
            for(int i=0;i<lists.length;i++){
                if(lists[i]==null){
                    count++;
                    continue;
                }
                if(lists[i].val<min){
                    min = lists[i].val;
                    index=i;
                }
            }
            if(count==lists.length)
                break;
            phead.next=lists[index];
            phead=phead.next;
            lists[index]=lists[index].next;
        }
        return head.next;
    }

解法二:

/**
     * Approach 3: Optimize Approach 2 by Priority Queue
     * @param lists
     * @return
     */
    public static ListNode mergeKLists2(ListNode[] lists){

        ListNode head = new ListNode(-1);
        ListNode phead = head;
        //構造優先隊列
        Queue<ListNode> minheap = new PriorityQueue<ListNode>(new Comparator<ListNode>() {
            @Override
            public int compare(ListNode o1, ListNode o2) {
                if(o1.val<o2.val)
                    return -1;
                else if(o1.val==o2.val)
                    return 0;
                else {
                    return 1;
                }
            }
        }); //初始化優先隊列
        for(ListNode l:lists){
            if(l!=null)
                minheap.add(l);
        }
        while(!minheap.isEmpty()){
            phead.next=minheap.poll();  //隊列的頭元素必爲所有鏈表頭元素中的最小值
            phead=phead.next;
            if(phead.next!=null)
                minheap.add(phead.next);
        }
        return head.next;
    }

解法三:

/**
     * 與歸併排序的思路相似
     * @param lists
     * @return
     */
    public static ListNode mergeKLists3(ListNode[] lists){

        int length=lists.length;
        int inteval=1;
        while(inteval<length){
            for(int i=0;i<length-inteval;i+=inteval*2){
                lists[i] = mergeTwoLists(lists[i],lists[i+inteval]);
            }
            inteval *=2;
        }
        return lists[0];
    }

32. Longest Valid Parentheses

Description:
Given a string containing just the characters ‘(’ and ‘)’, find the length of the longest valid (well-formed) parentheses substring.

Example 1:

Input: "(()"
Output: 2
Explanation: The longest valid parentheses substring is "()"

Example 2:

Input: ")()())"
Output: 4
Explanation: The longest valid parentheses substring is "()()"
/**
     * 32. Longest Valid Parentheses
     * Given a string containing just the characters '(' and ')', find the length of the longest valid (well-formed) parentheses substring
     * 思路:利用棧
     * 首先向入棧元素-1,作爲棧底元素,接着對於遍歷到的字符串元素“(”或")",我們有兩種處理方式:
     * 1)如果是“(”,則直接入棧
     * 2)如果是“)”,則要考慮兩種情況:
     * 第一種爲:如果此時棧裏面多於一個元素,則說明棧頂一定是“(”,我們只需要出棧此元素,並記錄合格的字符串長度就可以了
     * 第二種爲:棧頂只有一個元素(“)”或-1),此時我們只需要棧頂元素出棧,並將“)”入棧就可以了
     * Example 1:
     * Input: "(()"
     * Output: 2
     * Explanation: The longest valid parentheses substring is "()"
     * @param s
     * @return
     */
    public static int longestValidParentheses(String s) {
        if(s==null || s.equals(""))
            return 0;   
        //初始化一個棧
        Stack<Integer> stack = new Stack<>();
        stack.push(-1);
        int max=0;
        int count=0;    //計數,將匹配的括號對數記下來
        for(int i=0;i<s.length();i++){
            char ch = s.charAt(i);
            //如果是“(”,就用棧記錄下他的索引
            if(ch=='(')
                stack.push(i);
            else{
                //如果是“)”,則分爲兩種情況:棧的元素多餘一個,這時肯定可以配對;2)棧裏面只有一個元素,此時可以肯定是不能配對的
                stack.pop();
                if(!stack.isEmpty()){
                    count = i-stack.peek();
                    max = (max<count)? count:max;
                }else{
                    stack.push(i);
                }
            }
        }
        return max; 
    }
/**
     * 動態規劃解法
     * 用dp[i]來表示以i結束的字符串的最長合格字符串的長度,那麼很明顯“(”對應的都爲0
     * @return 
     * 
     */
    public static int longestValidParentheses2(String s){
        //邊界條件
        if(s==null || s.equals(""))
            return 0;
        int max =0,index=0;;
        int[] dp = new int[s.length()];
        for(int i=1;i<s.length();i++){
            char ch = s.charAt(i);
            if(ch == ')' && s.charAt(i-1)=='('){    //只更新")"的情況
                //第一種情況,前一個
                index = i-2;
                if(index>=0)
                    dp[i]=dp[i-2]+2;
                else
                    dp[i]=2;
            }
            if(ch == ')' && s.charAt(i-1)==')'){
                index = i-dp[i-1]-1;
                if(index>0 && s.charAt(index)=='(')
                    dp[i]=dp[i-1]+dp[index-1]+2;    // 
                else if(index==0 && s.charAt(index)=='(')
                    dp[i]=dp[i-1]+2;
                else {
                    dp[i]=0;
                }
            }
            max = max<dp[i] ? dp[i]:max;
        }
        return max;
    }

33. Search in Rotated Sorted Array

Description:
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

解法一:

/**
     * 33. Search in Rotated Sorted Array
     * Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
     * @param nums
     * @param target
     * @return
     */
    public static int search(int[] nums, int target){
        if(nums==null || nums.length<1)
            return -1;
        //查找支點
        int index=0,result=-1;
        for(;index+1<nums.length;index++){
            if(nums[index]>nums[index+1])
                break;
        }
        if(nums[0]<target){
            result=BinarySearch(nums,0,index,target);
        }else if(nums[0]>target)
            result=BinarySearch(nums,index+1,nums.length-1,target);
        else {
            return 0;
        }       
        return result;  
    }
    private static int BinarySearch(int[] nums,int start,int end,int target) {
        int mid=(start+end)/2;
        if(start<=end){
            if(nums[mid]<target)
                return BinarySearch(nums,mid+1,end,target);
            else if(nums[mid]>target)
                return BinarySearch(nums, start,mid-1,target);
            else
                return mid;
        }else{
            return -1;
        }
    }

解法二:


    public static int search2(int[] nums, int target){
        if(nums==null || nums.length<1)
            return -1;
        //查找支點
        int low=0,high=nums.length-1;
        while(low<=high){
            int mid=low+(high-low)/2;
            if(nums[mid]==target)
                return mid;
            //先區分mid的位置
            if(nums[mid]>=nums[low]){
                if(nums[low]<=target && target<nums[mid])
                    high=mid-1;
                else
                    low=mid+1;
            }else{
                if(target<=nums[high] && target>nums[mid])
                    low = mid+1;
                else
                    high=mid-1;
            }
        }
        return -1;  
    }

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

Description:
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]

解法一:

/**
     * 34. Find First and Last Position of Element in Sorted Array
     * @param nums
     * @param target
     * @return
     */
    public static int[] searchRange(int[] nums, int target) {

        int low=0,high=nums.length-1;
        int first=0,last=0;
        int[] result = {-1,-1};
        while(low<=high){
            int mid = (low+high)/2;
            if(nums[mid]<target)
                low=mid+1;
            else if(nums[mid]>target)
                high=mid-1;
            else {
                //從mid處向前後查找
                first=mid;last=mid;
                while(first>=0){
                    if(nums[first]!=nums[mid])
                        break;
                    first--;
                }
                result[0]=first+1;
                while(last<nums.length){
                    if(nums[last]!=nums[mid])
                        break;
                    last++;
                }
                result[1]=last-1;
            }
        }
        return result;
    }

解法二:

/**
     * 34. Find First and Last Position of Element in Sorted Array
     * 解法二
     * @param nums
     * @param target
     * @return
     */
    public static int[] searchRange2(int[] nums, int target) {
        int[] result = {-1,-1};
        if(nums==null)
            return result;
        result[0]=GetFirstTarget(nums, target);
        result[1]=GetLastTarget(nums, target);
        return result;
    }
    /**
     * 找出nums中第一個target的位置
     * @param nums
     * @param target
     * @return
     */
    public static int GetFirstTarget(int[] nums,int target){
        int low=0,high=nums.length-1;
        int result=-1;
        while(low<=high){
            int mid = (low+high)/2;
            if(nums[mid]==target){
                if(mid>0 && nums[mid-1]!=target || mid==0){
                    result=mid;
                    break;
                }
                high=mid-1;
            }else if(nums[mid]>target)
                high=mid-1;
            else {
                low = mid+1;
            }
        }
        return result;
    }
    /**
     * 找出nums中最後一個target的位置
     * @param nums
     * @param target
     * @return
     */
    public static int GetLastTarget(int[] nums,int target){
        int low=0,high=nums.length-1;
        int result=-1;
        while(low<=high){
            int mid = (low+high)/2;
            if(nums[mid]==target){
                if(mid<nums.length-1 && nums[mid+1]!=target || mid==nums.length-1){
                    result=mid;
                    break;
                }
                low=mid+1;
            }else if(nums[mid]>target)
                high=mid-1;
            else {
                low = mid+1;
            }
        }
        return result;
    }

35. Search Insert Position

Description:
Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.

You may assume no duplicates in the array.

Example 1:

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

Example 2:

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

Example 3:

Input: [1,3,5,6], 7
Output: 4

Example 4:

Input: [1,3,5,6], 0
Output: 0

解法一:

/**
     * 35. Search Insert Position
     * Given a sorted array and a target value, return the index if the target is found. 
     * If not, return the index where it would be if it were inserted in order.
     * Example 1:
     * Input: [1,3,5,6], 5
     * Output: 2
     * Example 2:
     * Input: [1,3,5,6], 2
     * Output: 1
     * Example 3:
     * Input: [1,3,5,6], 7
     * Output: 4
     * Example 4:
     * Input: [1,3,5,6], 0
     * Output: 0
     * @param nums
     * @param target
     * @return
     */
    public static int searchInsert(int[] nums, int target){
        if(nums==null || nums.length<1)
            return 0;
        int index=0;
        for(;index<nums.length;index++){
            if(nums[index]>=target){
                break;
            }               
        }
        return index;
    }

解法二:

public static int searchInsert1(int[] nums, int target) {
        if(nums==null || nums.length<1)
            return 0;
        int low = 0, high = nums.length-1;
        // Invariant: the desired index is between [low, high+1]
        while (low <= high) {
            int mid = low + (high-low)/2;

            if (nums[mid] < target)
                low = mid+1;
            else if(nums[mid] >target)
                high = mid-1;
            else {
                return mid;
            }
        }
        // (1) At this point, low > high. That is, low >= high+1
        // (2) From the invariant, we know that the index is between [low, high+1], so low <= high+1. Follwing from (1), now we know low == high+1.
        // (3) Following from (2), the index is between [low, high+1] = [low, low], which means that low is the desired index
        //     Therefore, we return low as the answer. You can also return high+1 as the result, since low == high+1
        return low;
    }

39. Combination Sum

Description:
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]
]
/**
     * 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.
     * @param args
     */
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        if(candidates == null || candidates.length<1)
            return result;
        //DFS
        combinationSum(candidates,target,0,new ArrayList<>(),result);
       return result;
    }
    /**
     * DFS算法計算數組中和爲target的所有組合
     * @param candidates 數組
     * @param target    目標值
     * @param i         當前遍歷到的數組索引
     * @param record    臨時記錄列表
     * @param result    最終返回列表
     */
    private void combinationSum(int[] candidates, int target, int index, List<Integer> record, List<List<Integer>> result) {

        if(target<0)
            return;
        if(target == 0){
            result.add(record);
            return;
        }
        for(int i=index;i<candidates.length;i++){
            target -=candidates[i]; //將candidates[i]加入target
            record.add(candidates[i]);
            combinationSum(candidates,target,i,record,result);
            target +=candidates[i]; //典型的回溯法結構
            record.remove(record.size()-1);
        }
    }

42. Trapping Rain Water

Description:
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.
這裏寫圖片描述

The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!

Example:

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

解法一:

/**
     * 42. Trapping Rain Water
     * Given n non-negative integers representing an elevation map 
     * where the width of each bar is 1, compute how much water it is able to trap after raining.
     * 思路:
     * 首先我們將當前的height[i]記錄爲front=height[i](假設能構成容器的前端高度)。那麼對於height[i+1],我們只考慮兩種情況:
     * 情況一:height[i+1]>=height[i]
     *      此時,二者沒有構成容器的可能,故我們可以置front=height[i+1],並記錄下此時的索引frontIndex=i+1;
     * 情況二:height[i+1]<height[i]
     *      此時,二者有構成容器的可能,我們記錄下可以容水的容積temp+=front-height[i+1],並繼續遍歷height[i+2]...height[length-1],
     *      如果其中遇到某個height[j]>=front,則我們將容積temp記錄到總容積max中去,並將front=height[j],frontIndex=j;max+=temp;temp=0;
     *      有一種特殊的情況就是當最後一個高度height[length-1]<front的時候,此時前面的解法存在問題,此時我們對於height[frontIndex]....height[length]
     *      要重新考慮,我們只需每一次將front--,並繼續遍歷就可以了
     * @param height
     * @return
     */
    public static int trap(int[] height){
        if(height==null || height.length<3)
            return 0;
        int max =0;//用於記錄最大的儲水容積
        int front=height[0],frontIndex=0;   //front表示容器的前端高度,back表示構成容器的後端高度
        int temp=0;
        for(int i=1;i<height.length;i++){
            if(height[i]>=front){   //如果height>=front,則可以構成容器
                front=height[i];    //
                frontIndex=i;
                max+=temp;          //將temp值添加到總的容積max
                temp=0;             //並將temp置爲0
            }
            else{
                temp+=front-height[i];  //temp記錄某個容器的容積
            }
            //對最後的高度要進行判斷,如果height[length-1]<front,則說明構不成容器,此時將front--
            if(i==height.length-1 && height[i]<front){
                temp=0;
                front--;        
                i=frontIndex;
            }
        }
        return max;
    }

解法二:

/**
     * 解法二:
     * 採用動態規劃的思想將index位置的左邊(i<=index)的最高值和右邊(i>index)的最高值記錄下來
     * @param height
     * @return
     */
    public static int trap2(int[] height){

        if(height==null || height.length<3)
            return 0;
        int[] leftMax = new int[height.length];
        int[] rightMax = new int[height.length];
        int water=0;
        leftMax[0]=height[0];
        for(int i=1;i<height.length;i++){
            leftMax[i] = Math.max(height[i],leftMax[i-1]);
        }
        rightMax[height.length-1]=height[height.length-1];
        for(int j=height.length-2;j>=0;j--)
            rightMax[j]=Math.max(height[j],rightMax[j+1]);
        for(int i=1;i<height.length-1;i++)
            water+=Math.min(leftMax[i],rightMax[i])-height[i];
        return water;

    }

46. Permutations

Description:
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]
]
/**
     * 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]]
     * 思路:把數組分爲兩部分,第一個數字爲前一部分,其他爲後一部分,依次交換;
     * 然後採用遞歸的思路
     * @param nums
     * @return
     */
    public static List<List<Integer>> permute(int[] nums) {
        //初始化鏈表
        List<List<Integer>> result = new LinkedList<>();
        if(nums==null || nums.length<1)
            return result;
        //int[] copy = Arrays.copyOf(nums,nums.length);
        allPermute(nums,0,result);
        return result;
    }
    /**
     * 遞歸思路
     * @param array
     * @param startIndex 指數組要替換的那個位置
     * @param result
     */
    public static void allPermute(int[] array,int startIndex,List<List<Integer>> result){
        if(startIndex == array.length){
            List<Integer> sublist = new LinkedList<>();
            for(int i=0;i<array.length;i++)
                sublist.add(array[i]);
            result.add(sublist);
            return;
        }
        int temp =array[startIndex];
        for(int i=startIndex;i<array.length;i++){

            if(i==startIndex)
                allPermute(array,startIndex+1, result);
            else{
                //先替換
                array[startIndex]=array[i];
                array[i]=temp;  
                allPermute(array,startIndex+1, result);
                //然後再換過來
                array[i]=array[startIndex];
                array[startIndex]=temp;
            }
        }
    }

48. Rotate Image

Description:
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]
]
/**
     * 48. Rotate Image
     * You are given an n x n 2D matrix representing an image.Rotate the image by 90 degrees (clockwise).
     * 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]
     * ]
     * @param matrix
     */
    /**
     * 思路,從最外面一層一次向裏層遍歷,每一次將4條邊上對應的位置依次互換即可
     * @param matrix
     */
    public void rotate(int[][] matrix) {
        int len = matrix.length;
        for(int i=0;i<len/2;++i){   //i表示遍歷的圈數
            for(int j=i;j<len-i-1;++j){ //j表示第i圈上元素的索引的範圍
                int tmp = matrix[i][j];
                matrix[i][j] = matrix[len-j-1][i];  //替換上邊的元素
                matrix[len-j-1][i] = matrix[len-i-1][len-j-1];  //替換左邊上的元素
                matrix[len-i-1][len-j-1] = matrix[j][len-i-1];
                matrix[j][len-i-1] = tmp;
            }
        }
    }

49. Group Anagrams

Description:
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.

解法一:

/**
     * 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.
     * @param strs
     * @return
     */
    /**
     * 解法一:暴力解法(時間複雜度太大)
     **/
    public List<List<String>> groupAnagrams(String[] strs) {
        //
        String flag="-1";   //flag用來標記已經訪問過的數組元素
        List<List<String>> result = new LinkedList<>();
        if(strs==null || strs.length<1)
            return result;

        for(int i=0;i<strs.length;i++){
            if(!strs[i].equals(flag)){
                List<String> temp = new LinkedList<>();
                for(int j=i+1;j<strs.length;j++){
                    if(!strs[j].equals(flag) && isAnagrams(strs[i],strs[j])){   //如果二者是重組字
                        temp.add(strs[j]);
                        strs[j]=flag;
                    }
                }
                temp.add(strs[i]);
                strs[i]=flag;
                result.add(temp);
            }
        }
        return result;
    }
    /**
     * 判斷兩個字符串是否是Anagrams
     * @param string
     * @param string2
     * @return
     */
    private boolean isAnagrams(String string, String string2) {
        if(string==null || string2==null || string.length()!=string2.length())
            return false;
        else{
            StringBuffer compare = new StringBuffer(string2);
            for(int i=0;i<string.length();i++){
                String ch = string.substring(i,i+1);
                if(!compare.toString().contains(ch))
                    return false;
                int index = compare.indexOf(ch);
                compare.delete(index,index+1);
            }
        }
        return true;
    }

解法二:

/**
     * 解法二:將數組中的字符串排序,那麼是anagrams的字符串排序之後一定是相同的
     * 時間複雜度(NKLOG(K))
     * @param strs
     * @return
     */
    public List<List<String>> groupAnagrams2(String[] strs) {

        HashMap<String,List<String>> map = new HashMap<>();
        if(strs==null || strs.length<1)
            return new ArrayList<>();

        for(int i=0;i<strs.length;i++){
            char[] ch = strs[i].toCharArray();
            Arrays.sort(ch);
            String key = String.valueOf(ch);
            if(!map.containsKey(key))
                map.put(key,new ArrayList<String>());
            map.get(key).add(strs[i]);
        }
        return new ArrayList<>(map.values());
    }

解法三:

/**
     * 解法三:用26個字母對應的數組來計數每一個字母出現的次數,則次數相同的一定是Anagrams
     * @param args
     */
    public List<List<String>> groupAnagrams3(String[] strs){

        HashMap<String,List<String>> map = new HashMap<>();
        if(strs==null || strs.length<1)
            return new ArrayList<>();
        int[] count = new int[26];
        for(int i=0;i<strs.length;i++){
            Arrays.fill(count,0);
            for(char ch:strs[i].toCharArray())
                count[ch-'a']++;

            StringBuffer sb = new StringBuffer();
            for(int j=0;j<26;j++){
                sb.append('#');
                sb.append(count[j]);
            }
            String key = sb.toString(); //注意要轉換成String,否則StringBuffer不能比較字符串
            if(!map.containsKey(key))
                map.put(key,new ArrayList<>());
            map.get(key).add(strs[i]);
        }
        return new ArrayList<>(map.values());
    }

53. Maximum Subarray

Description:
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.

/**
     * 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.
     * @param nums
     * @return
     */
    public int maxSubArray(int[] nums) {
        if(nums==null || nums.length<1)
            return 0;

        int max=nums[0],temp=nums[0];   //temp用於計算nums[i]之前的連續數組的和最大值
        for(int i=1;i<nums.length;i++){
            if(temp<0)  //num[i]之前的連續數組之和大於0,則繼續尋找連續子數組,如果小於等於0,則重新賦值計算,並將之前的最大值存儲下來
                temp=0;
            temp+=nums[i];
            max = (max>=temp)? max:temp;
        }
        return max;
    }

55. Jump Game

Description:
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.

解法一:

/**
     * 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.
     * @param nums
     * @return
     */

    public boolean canJump(int[] nums) {
        if(nums==null || nums.length<1)
            return false;
        if(nums.length>1){
            int farIndex =0;    //記錄可以跳到的最遠的INdex
            for(int i=0;i<nums.length;i++){
                if(i>=farIndex && nums[i]==0 && i!=nums.length-1)   //注意最後一步爲0的情況
                    return false;
                else
                    farIndex = Math.max(farIndex,i+nums[i]);

            }
        }
        return true;
    }
/**
     * 解法二:倒序
     * @param nums
     * @return
     */
    public boolean canJump2(int[] nums) {
        int lastIndex = nums.length - 1;
        for(int i = nums.length - 2; i>=0; i--){
            if(nums[i]+i>=lastIndex){
                lastIndex = i;
            }            
        }
        return lastIndex == 0;        
    }

拓展:

45. Jump Game II

/**
     * 45. Jump Game II
     * 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.
     * Your goal is to reach the last index in the minimum number of jumps.
     * Example:
     * Input: [2,3,1,1,4]
     * Output: 2
     * Explanation: The minimum number of jumps to reach the last index is 2.
     * Jump 1 step from index 0 to 1, then 3 steps to the last index.
     * Note:
     * You can assume that you can always reach the last index.
     * @param nums
     * @return
     */
    /**
     * 解法一:暴力解法,用DFS,時間複雜度超了
     */
    public int minstep;
    public int jumpII(int[] nums){
        minstep=nums.length;
        getAllPossibleSteps(nums,0,0);
        return minstep;
    }
    /**
     * 計算所有可能的到達最後一步的步數
     * @param nums
     * @param curPostion  當前所在的位置
     * @param count目前跳的步數
     * @param minstep 最小的步數
     */
    private void getAllPossibleSteps(int[] nums,int curPostion,int count){
        if(curPostion>=nums.length-1){
            minstep = count;
            return;
        }
        for(int i=nums[curPostion];i>0;i--){
            if(count>=minstep)
                break;
            getAllPossibleSteps(nums,curPostion+i,count+1);
        }
    }
    /**
     * 解法二:
     * 每一次在能跳到的範圍之內選擇下一次跳得最遠的點爲候選的跳點,這樣跳的次數應該最少
     * @param nums
     * @return
     */
    public int jumpII2(int[] nums){

        int count=0,curPostion=0;   //當前所在的位置
        while(curPostion<nums.length-1){
            count++;
            if(curPostion+nums[curPostion]>=nums.length-1)
                break;
            else
                curPostion = getNexPositon(nums,curPostion);    //下一個最合適的跳點
        }
        return count;
    }
    /**
     * 計算能跳到的範圍之內的最適合的跳點
     * @param nums
     * @param curPostion
     * @return
     */
    private int getNexPositon(int[] nums, int curPostion) {

        int candiPostion =curPostion+1; //候選的跳點位置
        int farestPotion =curPostion;   //下一步能夠跳到的最遠的位置
        for(int i= curPostion+1;i<=curPostion+nums[curPostion];i++){
            if(i+nums[i]>farestPotion){
                candiPostion=i;
                farestPotion = i+nums[i];
            }
        }   
        return candiPostion;
    }
    /**
     * 解法三:
     * The main idea is based on greedy. Let's say the range of the current jump is [curBegin, curEnd], 
     * curFarthest is the farthest point that all points in [curBegin, curEnd] can reach. 
     * Once the current point reaches curEnd, then trigger another jump, 
     * and set the new curEnd with curFarthest, then keep the above steps, as the following:
     * @param A
     * @return
     */
    public int jumpII3(int[] A) {
        int jumps = 0, curEnd = 0, curFarthest = 0;
        for (int i = 0; i < A.length - 1; i++) {
            curFarthest = Math.max(curFarthest, i + A[i]);
            if (i == curEnd) {
                jumps++;
                curEnd = curFarthest;
            }
        }
        return jumps;
    }

56. Merge Intervals

Description:
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 considerred overlapping.
/**
 * Definition for an interval.
 * public class Interval {
 *     int start;
 *     int end;
 *     Interval() { start = 0; end = 0; }
 *     Interval(int s, int e) { start = s; end = e; }
 * }
 */
/**
     * 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 considerred overlapping.
     * 思路:
     * 首先根據間隔的start值將集合重新排序,然後再進行合併
     * @param intervals
     * @return
     */
    public List<Interval> merge(List<Interval> intervals){
        List<Interval> result = new ArrayList<Interval>();
        if(intervals == null || intervals.size()<1)
            return result;
        //對列表排序
        Collections.sort(intervals,new Comparator<Interval>() {

            public int compare(Interval o1, Interval o2) {              
                return o1.start-o2.start;
            }
        });
        int start=intervals.get(0).start,end=intervals.get(0).end;
        for(int i=1;i<intervals.size();i++){
            if(intervals.get(i).start<=end){
                end = Math.max(end,intervals.get(i).end);
            }
            else{
                result.add(new Interval(start,end));
                start = intervals.get(i).start;
                end = intervals.get(i).end;
            }
        }
        result.add(new Interval(start,end));
        return result;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章