【Lintcode】1148. Longest Harmonious Subsequence

題目地址:

https://www.lintcode.com/problem/longest-harmonious-subsequence/description

給定一個數組,求其最大值與最小值之差正好是11的最長子序列的長度。

法1:哈希表。先用哈希表記錄每個數字出現了多少次,然後再遍歷數組,直接計算當前值和其加上11兩個數字出現次數之和(當然當前值加11這個數字未必出現在哈希表裏了,所以還需要判斷一下),並且更新已知答案即可。代碼如下:

import java.util.HashMap;
import java.util.Map;

public class Solution {
    /**
     * @param nums: a list of integers
     * @return: return a integer
     */
    public int findLHS(int[] nums) {
        // write your code here
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        int res = 0;
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            map.put(nums[i], map.getOrDefault(nums[i], 0) + 1);
        }
    
        for (int i = 0; i < nums.length; i++) {
            if (map.containsKey(nums[i] + 1)) {
                res = Math.max(res, map.get(nums[i]) + map.get(nums[i] + 1));
            }
        }
        
        return res;
    }
}

時空複雜度O(n)O(n)

法2:排序 + 雙指針。可以先對數組進行排序,然後用前後雙指針。先走前指針直到遇到一個不同數字,如果該數字與後指針所指的數字正好差11,則更新最終答案;否則的話,看一下後指針前一個數字是否和自己所指數字相差11,如果是,那就將前指針指向那個前一個數字第一次出現的位置(可以用哈希表存儲),如果不是,則直接將前指針移動到後指針的位置上。代碼如下:

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class Solution {
    /**
     * @param nums: a list of integers
     * @return: return a integer
     */
    public int findLHS(int[] nums) {
        // write your code here
        if (nums == null || nums.length == 0) {
            return 0;
        }
    
        Arrays.sort(nums);
        // 記錄每個數字第一次出現的位置
        Map<Integer, Integer> map = new HashMap<>();
        int res = 0;
        // l是後指針,或者左指針,慢指針
        int l = 0;
        // r是前指針,或者右指針,快指針
        for (int r = 0; r < nums.length; r++) {
        	// 記錄一下每個數字第一次出現的位置
            map.putIfAbsent(nums[r], r);
            // 如果前後兩個指針指向數字相同,則移動前指針
            if (nums[r] == nums[l]) {
                continue;
            }
            
            if (nums[r] == nums[l] + 1) {
            	// 如果剛好前指針所指數和後指針所指數滿足關係,則更新最大長度
                res = Math.max(res, r - l + 1);
            } else {
            	// 否則分兩種情況討論。如果前指針前一個數字和自己所指數字正好滿足條件,
            	// 則將後指針走到前一個數第一次出現的地方;
            	// 否則直接走到r的位置上去
                if (nums[r] == nums[r - 1] + 1) {
                    l = map.get(nums[r - 1]);
                } else {
                    l = r;
                }
            }
        }
        
        return res;
    }
}

時間複雜度O(nlogn)O(n\log n),空間O(n)O(n)

算法正確性證明:
數學歸納法。如果數組長度爲11或者22顯然正確。假設數組長度小於等於nn都正確,當數組長度爲n+1n+1時,首先前指針一定會走到第一個不等於數組首個數的地方,此時如果這兩個數正好滿足條件,那麼前指針會繼續走到下一個更大的數(或者走到末尾),如果走到末尾,算法顯然成立;否則的話,如果這個更大的數和之前那個數滿足條件,那麼後指針應當指向之前那個數第一次出現的地方,由歸納假設,算法對長度更短的數組也是對的;回到前指針走到第一個不等於數組首個數的地方這個邏輯起點,如果該數與之前那個數不滿足條件,那麼後指針應當移動到前指針所在的位置,這樣問題又轉化爲長度更短的數組了,由歸納假設,算法是對的。再由數學歸納法知道算法成立。

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