題目地址:
https://www.lintcode.com/problem/longest-harmonious-subsequence/description
給定一個數組,求其最大值與最小值之差正好是的最長子序列的長度。
法1:哈希表。先用哈希表記錄每個數字出現了多少次,然後再遍歷數組,直接計算當前值和其加上兩個數字出現次數之和(當然當前值加這個數字未必出現在哈希表裏了,所以還需要判斷一下),並且更新已知答案即可。代碼如下:
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;
}
}
時空複雜度。
法2:排序 + 雙指針。可以先對數組進行排序,然後用前後雙指針。先走前指針直到遇到一個不同數字,如果該數字與後指針所指的數字正好差,則更新最終答案;否則的話,看一下後指針前一個數字是否和自己所指數字相差,如果是,那就將前指針指向那個前一個數字第一次出現的位置(可以用哈希表存儲),如果不是,則直接將前指針移動到後指針的位置上。代碼如下:
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;
}
}
時間複雜度,空間。
算法正確性證明:
數學歸納法。如果數組長度爲或者顯然正確。假設數組長度小於等於都正確,當數組長度爲時,首先前指針一定會走到第一個不等於數組首個數的地方,此時如果這兩個數正好滿足條件,那麼前指針會繼續走到下一個更大的數(或者走到末尾),如果走到末尾,算法顯然成立;否則的話,如果這個更大的數和之前那個數滿足條件,那麼後指針應當指向之前那個數第一次出現的地方,由歸納假設,算法對長度更短的數組也是對的;回到前指針走到第一個不等於數組首個數的地方這個邏輯起點,如果該數與之前那個數不滿足條件,那麼後指針應當移動到前指針所在的位置,這樣問題又轉化爲長度更短的數組了,由歸納假設,算法是對的。再由數學歸納法知道算法成立。