關於數組的算法題(一)


 數組方法:

1、length:

   arr.length返回數組長度

 2、Arrays.asList()

  將數組轉化成List集合的方法。

 3、Arrays.fill()函數

填充a1數組中的每個元素都是value。

Arrays.fill( a1, value );

注:a1是一個數組變量,value是一個a1中元素數據類型的值。

 

1、長度最小的子數組

給定一個含有 n 個正整數的數組和一個正整數 s ,找出該數組中滿足其和 ≥ s 的長度
最小的連續子數組,並返回其長度。如果不存在符合條件的連續子數組,返回 0。
示例:
輸入: s = 7 , n u m s = [ 2 , 3 , 1 , 2 , 4 , 3 ]
輸出: 2
解釋: 子數組 [ 4 , 3 ] 是該條件下的長度最小的連續子數組。
 

暴力破解法:

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int min = Integer.MAX_VALUE;
        for(int i =0;i<nums.length;i++){
            int sum = nums[i];
            if(sum >= target){
                return 1;
            }
            for(int j = i+1; j<nums.length;j++){
                sum += nums[j];
                if(sum >= target){
                    min = Math.min(min,j-i+1);
                }
            }
        }
        return min == Integer.MAX_VALUE ? 0 : min;
    }
}

 

2、尋找兩個正序數組的中位數

給定兩個大小分別為 m 和 n 的正序(從小到大)數組 nums1 和 nums2。請你找出並返回這兩個正序數組的 中位數 。

示例 1:

輸入:nums1 = [1,3], nums2 = [2]
輸出:2.00000
解釋:合並數組 = [1,2,3] ,中位數 2


示例 2:

輸入:nums1 = [1,2], nums2 = [3,4]
輸出:2.50000
解釋:合並數組 = [1,2,3,4] ,中位數 (2 + 3) / 2 = 2.5


示例 3:

輸入:nums1 = [0,0], nums2 = [0,0]
輸出:0.00000


示例 4:

輸入:nums1 = [], nums2 = [1]
輸出:1.00000


示例 5:

輸入:nums1 = [2], nums2 = []
輸出:2.00000

 

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int[] nums;
        int m = nums1.length;
        int n = nums2.length;
        nums = new int[m+n];
        if(m == 0){
            if(n % 2 == 0){
                return (nums2[n/2 - 1] + nums2[n/2]) / 2.0;
            }else{
                return nums2[n/2];
            }
        }
        if(n == 0){
            if(m % 2 == 0){
                return (nums1[m/2 - 1] + nums1[m/2]) / 2.0;
            }else{
                return nums1[m/2];
            }
        }
        int count = 0;
        int i = 0;
        int j = 0;
        while(count != (m + n)){
            if(i == m){
                while(j != n){
                    nums[count++] = nums2[j++];
                }
                break;
            }
            if(j == n){
                while(i != m){
                    nums[count++] = nums1[i++];
                }
                break;
            }
            
            if(nums1[i] < nums2[j]){
                nums[count] = nums1[i];
                count++;
                i++;
            }else{
                nums[count] = nums2[j];
                count++;
                j++;
            }
            
        }
        if((m+n) % 2 == 0){
            return (nums[(m+n)/2 - 1] + nums[(m+n) / 2]) / 2.0;
        }else{
            return nums[(m+n) / 2] ;
        }
    }
}

解析:

  暴力破解法:先將兩個數組合並,兩個有序數組的合並也是歸並排序中的一部分。然后根據奇數,還是偶數,返回中位數。

 

3、數組中重復的數據

給定一個整數數組 a,其中1 ≤ a[i] ≤ n (n為數組長度), 其中有些元素出現兩次而其他元素出現一次。

找到所有出現兩次的元素。

示例:

輸入:
[4,3,2,7,8,2,3,1]

輸出:
[2,3]
class Solution {
    public List<Integer> findDuplicates(int[] nums) {
        List<Integer> res = new ArrayList<>();
        if(nums == null || nums.length == 0){
            return res;
        }
        Set<Integer> set = new HashSet<>();
        for(int n : nums){
            if(!set.add(n)){
                res.add(n);
            }
        }
        return res;
    }
}

 

4、找到所有數組中消失的數字

給你一個含 n 個整數的數組 nums ,其中 nums[i] 在區間 [1, n] 內。請你找出所有在 [1, n] 范圍內但沒有出現在 nums 中的數字,並以數組的形式返回結果。

示例 1:

輸入:nums = [4,3,2,7,8,2,3,1]
輸出:[5,6]

示例 2:

輸入:nums = [1,1]
輸出:[2]

class Solution {
    public List<Integer> findDisappearedNumbers(int[] nums) {
        List<Integer> res = new ArrayList<>();
        if(nums == null || nums.length == 0){
            return res;
        }
        int[] tmp = new int[nums.length]; 
        for(int n : nums){
            if(n >= 1 && n <= nums.length){
                tmp[n - 1] = 1;
            }
        }
        for(int i=0;i<nums.length;i++){
            if(tmp[i] == 0){
                res.add(i+1);
            }
        }
        return res;
    }
}

 

5、二分查找

給定一個 n 個元素有序的(升序)整型數組 nums 和一個目標值 target  ,寫一個函數搜索 nums 中的 target,如果目標值存在返回下標,否則返回 -1。

輸入: nums = [-1,0,3,5,9,12], target = 9
輸出: 4
解釋: 9 出現在 nums 中並且下標為 4
輸入: nums = [-1,0,3,5,9,12], target = 2
輸出: -1
解釋: 2 不存在 nums 中因此返回 -1

 

class Solution {
    public int search(int[] nums, int target) {
        if(nums[0] > target || nums[nums.length - 1] < target){
            return -1;
        }
        int left = 0;
        int right = nums.length;
        while(left < right){
            int middle = (left + right) / 2;
            if(nums[middle] > target){
                right = middle;
            }else if(nums[middle] < target){
                left = middle + 1;
            }else{
                return middle;
            }
        }
        return -1;
    }
}

解析:

  這道題目的前提是數組為有序數組,同時題目還強調數組中無重復元素,因為一旦有重復元素,使用二分查找法返回的元素下標可能不是唯一的,這些都是使用二分法的前提條件,當大家看到題目描述滿足如上條件的時候,可要想一想是不是可以用二分法了。

二分查找涉及的很多的邊界條件,邏輯比較簡單,但就是寫不好。例如到底是 while(left < right) 還是 while(left <= right),到底是right = middle呢,還是要right = middle - 1呢?

大家寫二分法經常寫亂,主要是因為對區間的定義沒有想清楚,區間的定義就是不變量。要在二分查找的過程中,保持不變量,就是在while尋找中每一次邊界的處理都要堅持根據區間的定義來操作,這就是循環不變量規則。

寫二分法,區間的定義一般為兩種,左閉右閉即[left, right],或者左閉右開即[left, right)。

下面我用這兩種區間的定義分別講解兩種不同的二分寫法。

二分法第一種寫法

第一種寫法,我們定義 target 是在一個在左閉右閉的區間里,也就是[left, right] (這個很重要非常重要)。

區間的定義這就決定了二分法的代碼應該如何寫,因為定義target在[left, right]區間,所以有如下兩點:

  • while (left <= right) 要使用 <= ,因為left == right是有意義的,所以使用 <=
  • if (nums[middle] > target) right 要賦值為 middle - 1,因為當前這個nums[middle]一定不是target,那么接下來要查找的左區間結束下標位置就是 middle - 1

例如在數組:1,2,3,4,7,9,10中查找元素2,如圖所示:

704.二分查找

二分法第二種寫法

如果說定義 target 是在一個在左閉右開的區間里,也就是[left, right) ,那么二分法的邊界處理方式則截然不同。

有如下兩點:

  • while (left < right),這里使用 < ,因為left == right在區間[left, right)是沒有意義的
  • if (nums[middle] > target) right 更新為 middle,因為當前nums[middle]不等於target,去左區間繼續尋找,而尋找區間是左閉右開區間,所以right更新為middle,即:下一個查詢區間不會去比較nums[middle]

在數組:1,2,3,4,7,9,10中查找元素2,如圖所示:(注意和方法一的區別)

704.二分查找1

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM