一題算法|求最長和諧子序列

和諧子序列的定義

和諧數組是指一個數組裏元素的最大值和最小值之間的差別正好是1,也就是說我們需要找出比該元素大於或者相等的元素

LeetCode 題目:

給定一個整數數組,你需要在所有可能的子序列中找到最長的和諧子序列的長度

題目示例:

輸入: [1,3,2,2,5,2,3,7]
輸出: 5
原因: 最長的和諧數組是:[3,2,2,2,3].

解法一:暴力枚舉法

暴力枚舉的思想很簡單,也是我們常用的方法,就是雙重遍歷數組,第一層遍歷是枚舉數組中的每一個元素並且假設該元素是數組中最小的元素,第二層遍歷是枚舉元素與該數組中的每一個元素逐一比較,找出等於枚舉元素或者比枚舉元素大一的元素,統計出最終的元素個數。

1、解題代碼

/**
 * 使用暴力枚舉的方式
 * 雙重循環,每次以當前遍歷的元素當作最小元素,然後統計該數組中比該元素大1的個數或者相等的元素,最後返回最大的那個數
 *
 * @param nums 傳入的數組
 * @return
 */
public static int findLHS(int[] nums) {
    // 記錄最大的和諧子序列長度
    int res = 0;

    // 第一層遍歷,當前元素默認爲最小的元素
    for (int i = 0; i < nums.length; i++) {
        // 當前元素最長的子序列長度
        int count = 0;
        // 第二層遍歷,與數組中的每一個元素進行比較,找出 nums[i]+1 = nums[j] 或者 nums[i]==nums[j] 的元素個數
        for (int j = 0; j < nums.length; j++) {
            if (nums[i] + 1 == nums[j] || nums[i] == nums[j]) {
                count += 1;
            }
        }
        // 將最大的賦值給res
        res = Math.max(count, res);
    }
    return res;
}

2、複雜度分析

時間複雜度:因爲是雙層循環遍歷,所以時間複雜度是O(N^2)

空間複雜度:在雙層遍歷中,並沒有產生額外的數組,只是定義了兩個臨時遍歷,所以空間複雜度爲O(1)

解法二:兩次遍歷 + HashMap

HashMap + 兩次遍歷的思想也比較簡單,第一次遍歷是統計每個元素出現的次數,並且將元素的值作爲key,出現的次數作爲val 存入到 HashMap 中,第二次遍歷是遍歷 HashMap ,判斷 HashMap 中是否存在比當前key+1的key,如果存在這統計出這兩個key一共出現的次數,最後返回出現最多的次數。

1、解題代碼

/**
 * hashMap + 兩次循環
 * 第一次循環是統計每個元素出現的個數
 * 第二次循環是遍歷HashMap 集合,判斷map集合中是否存在比當前key大於1的key,如果存在就統計兩個key一共出現的次數
 *
 * @param nums
 * @return
 */
public static int findLHSByHashMap(int[] nums) {
    // 記錄最大的和諧子序列長度
    int res = 0;
    Map<Integer, Integer> hashMap = new HashMap<>();
    // 第一層遍歷,當前元素默認爲最小的元素
    for (int i = 0; i < nums.length; i++) {
        hashMap.put(nums[i], hashMap.getOrDefault(nums[i], 0) + 1);
    }

    // 遍歷整個map
    for (int key : hashMap.keySet()) {
        if (hashMap.containsKey(key + 1)) {
            res = Math.max(res, hashMap.get(key) + hashMap.get(key + 1));
        }
    }
    return res;
}

2、複雜度分析

時間複雜度:雖然遍歷了兩次,但是沒有出現雙層循環,所以時間複雜度是O(N)

空間複雜度:這裏新增了 HashMap 的對象,所以空間複雜度爲O(N)

解法三:單次遍歷 + HashMap

這種方法是前面一種方法的優化,將兩次循環優化成一次循環,可以提升代碼的執行效率,思想也比較簡單,就是將元素 X 添加到 Map 集合後,同時判斷出 X 與 X-1 組成的和諧數組長度和 X 與 X+1 組成的和諧數組長度,取兩者中最大的一個。

1、解題代碼

/**
 * hashmap+單次遍歷
 * 是一種方法中的改進,在將元素添加到 map 的時候
 * 就計算出計算出元素 X 與 X-1 的和諧數組的長度和 X 與 X+1 的和諧數組長度
 * 這種方式雖然時間複雜度跟上一種沒什麼區別,但是可以節約執行時間
 * @param nums
 * @return
 */
public static int findLHSByMap(int[] nums) {
    // 記錄最大的和諧子序列長度
    int res = 0;
    Map<Integer, Integer> hashMap = new HashMap<>();
    // 第一層遍歷,當前元素默認爲最小的元素
    for (int i = 0; i < nums.length; i++) {
        hashMap.put(nums[i], hashMap.getOrDefault(nums[i], 0) + 1);
        // 判斷是否包含key+1的key
        if (hashMap.containsKey(nums[i] + 1)) {
            res = Math.max(res, hashMap.get(nums[i]) + hashMap.get(nums[i] + 1));
        }
        // 判斷是否包含key-1的key
        if (hashMap.containsKey(nums[i] - 1)) {
            res = Math.max(res, hashMap.get(nums[i]) + hashMap.get(nums[i] - 1));
        }
    }

    return res;
}

2、複雜度分析

時間複雜度:跟上面一樣,時間複雜度是O(N)

空間複雜度:跟上面一樣,空間複雜度爲O(N)

最後

歡迎掃碼關注微信公衆號:「平頭哥的技術博文」,和平頭哥一起學習,一起進步。

平頭哥的技術博文

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