LeetCode:Array

1.Array

1.Contains Duplicate

Given an array of integers, find if the array contains any duplicates. Your function should return true if any value appears at least twice in the array, and it should return false if every element is distinct.

運用merge sort的實現:

public class Solution {

    //success 1
    //運用merge sort的思想,如果在sort或merge中有相同的情況,那麼返回true,否則爲false。時間複雜度爲O(NlogN)
    public boolean containsDuplicate(int[] nums) {
        return sort(nums,0,nums.length-1);
    }

    /* Java program for Merge Sort */
        // Merges two subarrays of arr[].
        // First subarray is arr[l..m]
        // Second subarray is arr[m+1..r]
        boolean merge(int arr[], int l, int m, int r)
        {
            // Find sizes of two subarrays to be merged
            int n1 = m - l + 1;
            int n2 = r - m;

        /* Create temp arrays */
            int L[] = new int [n1];
            int R[] = new int [n2];

        /*Copy data to temp arrays*/
            for (int i=0; i<n1; ++i)
                L[i] = arr[l + i];
            for (int j=0; j<n2; ++j)
                R[j] = arr[m + 1+ j];


        /* Merge the temp arrays */

            // Initial indexes of first and second subarrays
            int i = 0, j = 0;

            // Initial index of merged subarry array
            int k = l;
            while (i < n1 && j < n2)
            {
                if (L[i] < R[j])
                {
                    arr[k] = L[i];
                    i++;
                }
                else if(L[i] > R[j])
                {
                    arr[k] = R[j];
                    j++;
                }else{
                    return true;
                }
                k++;
            }

        /* Copy remaining elements of L[] if any */
            while (i < n1)
            {
                arr[k] = L[i];
                i++;
                k++;
            }

        /* Copy remaining elements of L[] if any */
            while (j < n2)
            {
                arr[k] = R[j];
                j++;
                k++;
            }
            return false;
        }

        // Main function that sorts arr[l..r] using
        // merge()
        boolean sort(int arr[], int l, int r)
        {
            if (l < r)
            {
                // Find the middle point
                //注意:此種寫法容易引起溢出
                //int m = (l+r)/2;
                //正確寫法
                int m = l+(r-l)/2;
                // Sort first and second halves
                boolean left = sort(arr, l, m);
                boolean right = sort(arr , m+1, r);

                // Merge the sorted halves
                boolean merge =  merge(arr, l, m, r);
                if(left||right||merge){
                    return true;
                }
            }
            return false;
        }
}

此外,還有其他的一些方法,如果追求小的時間複雜度,可以用hashTable來實現。參考:

其他解法

2.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)).

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

我並沒有想出實現的方式,參考Discuss中大神的思路。自己動手實現一下:

public class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
    int m = nums1.length;
    int n = nums2.length;

    if (m > n) {
        return findMedianSortedArrays(nums2, nums1);
    }

    int i = 0, j = 0, imin = 0, imax = m, half = (m + n + 1) / 2;
    double maxLeft = 0, minRight = 0;
    while(imin <= imax){
        i = (imin + imax) / 2;
        j = half - i;
        if(j > 0 && i < m && nums2[j - 1] > nums1[i]){
            imin = i + 1;
        }else if(i > 0 && j < n && nums1[i - 1] > nums2[j]){
            imax = i - 1;
        }else{
            if(i == 0){
                maxLeft = (double)nums2[j - 1];
            }else if(j == 0){
                maxLeft = (double)nums1[i - 1];
            }else{
                maxLeft = (double)Math.max(nums1[i - 1], nums2[j - 1]);
            }
            break;
        }
    }
    if((m + n) % 2 == 1){
        return maxLeft;
    }
    if(i == m){
        minRight = (double)nums2[j];
    }else if(j == n){
        minRight = (double)nums1[i];
    }else{
        minRight = (double)Math.min(nums1[i], nums2[j]);
    }

    return (double)(maxLeft + minRight) / 2;
}
}

3.Find Peak Element

A peak element is an element that is greater than its neighbors.

Given an input array where num[i] ≠ num[i+1], find a peak element and return its index.

The array may contain multiple peaks, in that case return the index to any one of the peaks is fine.

You may imagine that num[-1] = num[n] = -∞.

For example, in array [1, 2, 3, 1], 3 is a peak element and your function should return the index number 2.

代碼如下:

public class Solution {

    //success 1
    // public int findPeakElement(int[] nums) {
    //     if(nums.length==1){
    //         return 0;
    //     }
    //     for (int i = 0; i < nums.length; i++) {
    //         if (i == 0) {
    //             if (nums[i] > nums[i + 1]) {
    //                 return 0;
    //             }
    //         } else if (i == nums.length - 1) {
    //             if (nums[i] > nums[i - 1]) {
    //                 return nums.length - 1;
    //             }
    //         } else {
    //             if (nums[i] > nums[i - 1] && nums[i] > nums[i + 1]) {
    //                 return i;
    //             }
    //         }

    //     }
    //     return 0;
    // }

    //success 2
    //簡化1
    public int findPeakElement(int[] nums) {
        for (int i = 1; i < nums.length; i++) {
            if(nums[i-1]>nums[i]){
                return i-1;
            }
        }
        return nums.length-1;
    }
}

除了上面兩種簡單的方法,還有O(logN)的方法:

This problem is similar to Local Minimum. And according to the given condition, num[i] != num[i+1], there must exist a O(logN) solution. So we use binary search for this problem.

1.If num[i-1] < num[i] > num[i+1], then num[i] is peak
2.If num[i-1] < num[i] < num[i+1], then num[i+1…n-1] must contains a peak
3.If num[i-1] > num[i] > num[i+1], then num[0…i-1] must contains a peak
4.If num[i-1] > num[i] < num[i+1], then both sides have peak

方法三代碼:

public class Solution {
    //success 3
    //運用binary search
    public int findPeakElement(int[] nums) {
        return findPeak(nums,0,nums.length-1);
    }

    public int findPeak(int[] num,int start,int end){
        if(start == end){
        return start;
    }else if(start+1 == end){
        if(num[start] > num[end]) return start;
        return end;
    }else{
        //注意:此種寫法容易引起溢出
        //int m = (start+end)/2;
        //正確寫法
        int m = start+(end-start)/2;
        //condition 1
        if(num[m] > num[m-1] && num[m] > num[m+1]){

            return m;
        //condition 3
        }else if(num[m-1] > num[m] && num[m] > num[m+1]){

            return findPeak(num,start,m-1);
        //condition 2 and conditon 4
        }else{

            return findPeak(num,m+1,end);

        }
    }

}
}

4.Find Minimum in Rotated Sorted Array

Suppose a sorted array 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).

Find the minimum element.

You may assume no duplicate exists in the array.

運用binary search,參考

public class Solution {
    public int findMin(int[] nums) {
        if (nums==null || nums.length==0) { return Integer.MIN_VALUE; } 
        int left = 0, right = nums.length-1;
        //保證比較數組中至少有三個元素
        while (left < right-1) {  // while (left < right-1) is a useful technique
            int mid = left + (right-left)/2;
            if (nums[mid] > nums[right]) { left = mid; }
            else { right = mid; }
        }
        if (nums[left] > nums[right]) { return nums[right]; }
        return nums[left];
    }
}

5.Find Minimum in Rotated Sorted Array II

4題上的變種(考慮有重複的元素):

Follow up for “Find Minimum in Rotated Sorted Array”:
What if duplicates are allowed?

Would this affect the run-time complexity? How and why?

public class Solution {
    public int findMin(int[] nums) {
        if (nums==null || nums.length==0) { return Integer.MIN_VALUE; } 
        int left = 0, right = nums.length-1;
        //保證比較數組中至少有三個元素
        while (left < right-1) {  // while (left < right-1) is a useful technique
            int mid = left + (right-left)/2;
            if (nums[mid] > nums[right]) { left = mid; }
            else if(nums[mid] < nums[right]) { right = mid; }
            //相等情況,不能確定在左還是右,只能減少一點邊界
            else{
                right-=1;
            }
        }
        if (nums[left] > nums[right]) { return nums[right]; }
        return nums[left];
    }
}

注意:Java曾經的一個系統級的binary search bug,可以google “binary search bug”,這個bug是,當使用int mid = (left + right)/2;時,如果當left和right都很大時,left+right將發生overflow,進而產生負數,Java在2006年已經在系統級別binary search上進行了修復。但是我們自己手寫代碼時,如果不注意這個bug,在left和right都很大時,就會產生錯誤。所以我推薦使用int mid = left + (right-left)/2;,當然最精確的方法是看看Java源碼中的實現,然後照着改寫之。
相關文章參考:
google blog
java bug

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