【精選】JAVA算法題(二十三)

一、完全平方數

題目:

/**
 *給定一個正整數 num,編寫一個函數,如果 num 是一個完全平方數,則返回 True,否則返回 False。
 * 說明:不要使用任何內置的庫函數,如  sqrt。
 *
 * 示例 1:
 * 輸入:16
 * 輸出:True
 *
 * 示例 2:
 * 輸入:14
 * 輸出:False
 */

不使用庫函數來判斷一個數是不是一個完全平方數-----》判斷該數開平方是不是一個整數------》從0到該數之前有沒有一個數字是該數開平方的根-----》二分查找 是否存在一個數的平方等於該數字

    public boolean method1(int num) {
        if(num == 0) return true;
        int left = 1, right = num < 46340 ? num : 46340, temp = 0;
        while(left <= right){
            temp = (left + (right - left) / 2);
            if(num > temp * temp){
                left = temp + 1;
            }else if(num == temp * temp){
                return true;
            }else{
                right = temp - 1;
            }
        }
        return false;
    }

利用數學知識,找規律

1=1

4=1+3

9=1+3+5

16=1+3+5+7

25=1+3+5+7+9

發現了嗎?完全平方數肯定是前n個連續奇數的和 n^2=1+3+5+7+9+…+(2n-1)

利用這樣規律從1開始減,不斷的減,看最後是否可以等於0;

    public boolean method2(int num) {
        int sumnum = 1; while(num>0){
            num-=sumnum;
            sumnum+=2;
        }
        return num==0;
    }

二、數組的交集 I

題目:

/**
 * 給定兩個數組,編寫一個函數來計算它們的交集。
 * <p>
 * 示例 1:
 * 輸入: nums1 = [1,2,2,1], nums2 = [2,2]
 * 輸出: [2]
 * <p>
 * 示例 2:
 * 輸入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
 * 輸出: [9,4]
 * <p>
 * 說明:
 * 輸出結果中的每個元素一定是唯一的。
 * 我們可以不考慮輸出結果的順序。
 */

如果這道題用python來解的話就十分簡單了,因爲python支持set運算,直接一行代碼就出來了

return list(set(nums1) & set(nums2))

java中也實現了功能相同的方法,不過set和數組轉換就不如python那般簡單了

    public int[] method1(int[] nums1, int[] nums2) {
        Set<Integer> integers = new HashSet<>();
        for (int a : nums1) {
            integers.add(a);
        }
        Set<Integer> integers1 = new HashSet<>();
        for (int a : nums2) {
            integers1.add(a);
        }
        integers.retainAll(integers1);
        int[] ints = new int[integers.size()];
        int i = 0;
        for (int a : integers) {
            ints[i] = a;
            i++;
        }
        return ints;
    }

也可以不使用該函數,而是自己去一個個判斷元素是否存在,實際上retainAll函數內部也是這麼實現的

    public int[] method2(int[] nums1, int[] nums2) {
        Set<Integer> set1 = new HashSet<>();
        Set<Integer> set2 = new HashSet<>();
        Set<Integer> set3 = new HashSet<>();
        for (int i : nums1) {
            set1.add(i);
        }
        for (int i : nums2) {
            if (set1.contains(i))
                set3.add(i);
        }
        int[] result = new int[set3.size()];
        int i = 0;
        for (Integer integer : set3) {
            result[i++] = integer;
        }
        return result;
    }

我們也可以先對其進行排序,隨後再用倆指針去判斷是否存在相等的元素,這樣的效率更高一些,但寫起來很是麻煩,需要很多判斷

    public int[] method3(int[] nums1, int[] nums2) {
        Arrays.sort(nums1);
        Arrays.sort(nums2);
        int i = 0,j=0,k=0;
        while (i < nums1.length && j < nums2.length) {
            if (nums1[i] == nums2[j]) {
                nums1[k++] = nums1[i];
                i++;
                while (i < nums1.length && nums1[i] == nums1[i - 1]) {
                    i++;
                }
                j++;
                while (j < nums2.length && nums2[j] == nums2[j - 1]) {
                    j++;
                }
            } else if (nums1[i] < nums2[j]) {
                i++;
                while (i < nums1.length && nums1[i] == nums1[i - 1]) {
                    i++;
                }
            } else {
                j++;
                while (j < nums2.length && nums2[j] == nums2[j - 1]) {
                    j++;
                }
            }
        }
        int[] ret = new int[k];
        for (int l = 0; l < k; l++) {
            ret[l] = nums1[l];
        }
        return ret;
    }

借鑑一下之前用過很多次的把元素轉換成數組下標的方式,一遍循環賦值,一遍循環查找並計數,一遍賦值數組,返回結果,因爲是操作的數組,所以這種的效率是最高的,但如果其中出的數字少但跨度大,所需的內存就會多出好多。

    public int[] method4(int[] nums1, int[] nums2) {
        // 確定數組 nums1 的取值範圍
        int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        for (int num : nums1) {
            if (num > max) {
                max = num;
            }
            if (num < min) {
                min = num;
            }
        }
        boolean[] arr = new boolean[max - min + 1];
        for (int num : nums1) {
            arr[num - min] = true;
        }
        // 判斷數組 nums2 中的數是否在數組 nums1 中存在,
        // 如果存在保存在數組 tmp 中
        int[] tmp = new int[max - min + 1];
        int idx = 0;
        for (int num : nums2) {
            if (num >= min && num <= max && arr[num - min]) {
                tmp[idx++] = num;
                arr[num- min] = false;
            }
        }
        // 返回結果
        int[] ret = new int[idx];
        for (int i = 0; i < idx; i++) {
            ret[i] = tmp[i];
        }
        return ret;
    }

三、數組的交集 II

題目:

/**
 * 給定兩個數組,編寫一個函數來計算它們的交集。
 *
 * 示例 1:
 * 輸入: nums1 = [1,2,2,1], nums2 = [2,2]
 * 輸出: [2,2]
 *
 * 示例 2:
 * 輸入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
 * 輸出: [4,9]
 *
 * 說明:
 *     輸出結果中每個元素出現的次數,應與元素在兩個數組中出現的次數一致。
 *     我們可以不考慮輸出結果的順序。
 *
 * 進階:
 *     如果給定的數組已經排好序呢?你將如何優化你的算法?
 *     如果 nums1 的大小比 nums2 小很多,哪種方法更優?
 *     如果 nums2 的元素存儲在磁盤上,磁盤內存是有限的,並且你不能一次加載所有的元素到內存中,你該怎麼辦?
 */

這道題就是上面那道題的進階,多了一個數字出現次數的規則。那第一時間想到的就是Map解決,先統計每個數字出現的次數,然後比對運算。代碼超簡單。

    public int[] method3(int[] nums1, int[] nums2) {
        HashMap<Integer,Integer> integerHashMap=new HashMap<>();
        for (int a:nums1){
            integerHashMap.put(a,integerHashMap.getOrDefault(a,0)+1);
        }
        ArrayList<Integer> integers=new ArrayList<>();
        for (int a:nums2){
            if (integerHashMap.get(a)!=null&&integerHashMap.get(a)>0){
                integerHashMap.put(a,integerHashMap.get(a)-1);
                integers.add(a);
            }
        }
        int[] ints=new int[integers.size()];
        for (int i=0;i<ints.length;i++){
            ints[i]=integers.get(i);
        }
        return ints;
    }

類似的事情也可以使用集合來實現啊,集合可以再比對完後使用remove移除指定元素

    public int[] method1(int[] nums1, int[] nums2) {
        List<Integer> list1 = new ArrayList<>();
        for (int num : nums1) {
            list1.add(num);
        }
        List<Integer> list2 = new ArrayList<>();
        for (int num : nums2) {
            if (list1.contains(num)) {
                list2.add(num);
                // 從 list1 除去已匹配的數值
                list1.remove(Integer.valueOf(num));
            }
        }
        int[] res = new int[list2.size()];
        int i = 0;
        for (int num : list2) {
            res[i++] = num;
        }
        return res;
    }

最近學了java8(出了好久好久了。。。。),來用java8寫一遍

    public int[] method2(int[] nums1, int[] nums2) {
        List<Integer> list1 = Arrays.stream(nums1)
                .boxed()
                .collect(Collectors.toList());
        List<Integer> list2 = Arrays.stream(nums2)
                .boxed()
                .filter(num -> {
                    if (list1.contains(num)) {
                        list1.remove(num);
                        return true;
                    }
                    return false;
                })
                .collect(Collectors.toList());
        int[] res = new int[list2.size()];
        for (int i = 0; i < list2.size(); i++) {
            res[i] = list2.get(i);
        }
        return res;
    }

還是像上一道題那樣預排序一下,然後使用兩個指針比對

    public int[] method4(int[] nums1, int[] nums2) {
        Arrays.sort(nums1);
        Arrays.sort(nums2);
        List<Integer> list = new ArrayList<>();
        for (int i = 0, j = 0; i < nums1.length && j < nums2.length; ) {
            if (nums1[i] < nums2[j]) {
                i++;
            } else if (nums1[i] > nums2[j]) {
                j++;
            } else {
                list.add(nums1[i]);
                i++;
                j++;
            }
        }
        int[] res = new int[list.size()];
        for (int i = 0; i < list.size(); i++) {
            res[i] = list.get(i);
        }
        return res;
    }

在java中可以使用Arrays.copyof來copy數組,如果只在數組上進行操作會快上不少,和上一種方法同一種思路,最後使用Arrays.copyof來替代一次for循環和list的使用。

    public int[] method5(int[] nums1, int[] nums2) {
        Arrays.sort(nums1);
        Arrays.sort(nums2);

        int i = 0, j = 0;
        int [] ans = new int [nums2.length];
        int index = 0;
        while(i++ < nums1.length && j++ < nums2.length){
            if(nums1[i - 1] == nums2[j - 1])
                ans[index++] = nums1[i - 1];
            else if(nums1[i - 1] < nums2[j - 1])
                j--;
            else
                i--;
        }
        return Arrays.copyOf(ans, index);
    }

 

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