LeetCode演算法題-Degree of an Array(Java實現)
這是悅樂書的第294 次更新,第312 篇原創
01 看題和準備
今天介紹的是LeetCode演算法題中Easy級別的第162題(順位題號是697)。給定一個由正整陣列成的非空陣列,該陣列的度數被定義為任意元素出現次數最多的次數。你的任務是找到一個(連續的)nums子陣列的最小可能長度,它與nums具有相同的度數。例如:
輸入:[1,2,2,3,1]
輸出:2
說明:輸入陣列的度數為2,因為元素1和2都出現兩次。在具有相同程度的子陣列中:[1,2,2,3,1],[1,2,2,3],[2,2,3,1],[1,2,2],[2,2,3],[2,2],最短的長度是2.所以返回2。
輸入:[1,2,2,3,1,4,2]
輸出:6
注意:
-
陣列長度將介於1到50,000之間。
-
陣列中的元素是0到49,999之間的整數。
本次解題使用的開發工具是eclipse,jdk使用的版本是1.8,環境是win7 64位系統,使用Java語言編寫和測試。
02 第一種解法
按照題目的意思,我們需要先把出現次數最多的元素找出來,然後再找到該元素第一次出現和最後一次出現的索引位置之間的距離,如果存在多個相同最多次數的元素,還需要比較他們之間的最小值。
因此,第一步,將陣列元素存入HashMap,得到最大次數;第二步,將出現最多次數的單個或多個元素新增進陣列;第三步,找到新陣列中每位元素出現的起始位置,計算距離長度,取其中的較小者。
public int findShortestSubArray(int[] nums) { if (nums == null || nums.length == 0) { return 0; } Map<Integer,Integer> map = new HashMap<Integer, Integer>(); int degree = 0; for (int num : nums) { map.put(num, map.getOrDefault(num, 0)+1); // 比較出現次數,取其中較大者 degree = Math.max(degree, map.get(num)); } // 將最多出現次數相同的元素放入新的陣列 int[] occur = new int[nums.length]; int index = 0; for (Integer key : map.keySet()) { if (map.get(key) == degree) { occur[index++] = key; } } int min = Integer.MAX_VALUE; // 遍歷新陣列,算出出現次數最多的元素在nums中的索引之差 for (int i=0; i< index; i++) { // 使用雙指標,一前一後遍歷nums,找到該元素的索引之差 int start = 0, end = nums.length-1; // 申明一個變數,儲存索引之差 int len = Integer.MAX_VALUE;; while (start <= end) { if (occur[i] == nums[start] && occur[i] == nums[end]) { len = end - start +1; break; } else if (occur[i] == nums[start] && occur[i] != nums[end]){ end--; } else if(occur[i] != nums[start] && occur[i] == nums[end]) { start++; } else { end--; start++; } } // 取兩者之間的最小值 min = Math.min(min, len); } return min; }
03 第二種解法
我們也可以不使用新陣列來存那些出現最多的元素,將HashMap的value型別改為陣列即可。依舊使用陣列中的元素作為key,value變成了一個包含三個元素的陣列,儲存次數、首次出現索引、最後一次出現索引,依舊是在第一次迴圈中就得到degree的值,然後遍歷HashMap的value,找到元素索引間隔最小的那個。
public int findShortestSubArray2(int[] nums) { if (nums == null || nums.length == 0) { return 0; } int degree = 0; // 以nums中的元素為key,以一個含有3個元素的陣列為value // 該陣列第一個元素為當前元素出現的次數,第二個元素為其第一次出現的位置,第三個元素為其最後一次出現的位置 Map<Integer,int[]> map = new HashMap<Integer, int[]>(); for (int i=0; i<nums.length; i++) { if (map.containsKey(nums[i])) { int[] temp = map.get(nums[i]); // 更新該元素出現次數 temp[0]++; // 更新該元素最後一次出現的位置(索引) temp[2] = i; } else { map.put(nums[i], new int[]{1, i, i}); } // 更新degree,取兩者之間較大值 degree = Math.max(degree, map.get(nums[i])[0]); } int min = Integer.MAX_VALUE; for (int[] values : map.values()) { if (values[0] == degree) { min = Math.min(min, values[2] - values[1] + 1); } } return min; }
04 第三種解法
對於第二種解法,我們可以再簡化下,只使用一個迴圈來處理。
public int findShortestSubArray3(int[] nums) { if (nums == null || nums.length == 0) { return 0; } int degree = 0; int min = Integer.MAX_VALUE; // 以nums中的元素為key,以一個含有2個元素的陣列為value // 該陣列第一個元素為當前元素出現的次數,第二個元素為其最後一次出現的位置 Map<Integer,int[]> map = new HashMap<Integer, int[]>(); for (int i=0; i<nums.length; i++) { if (!map.containsKey(nums[i])) { map.put(nums[i], new int[]{0, i}); } // 出現次數累加 map.get(nums[i])[0]++; // 對degree進行處理 if (degree < map.get(nums[i])[0]) { degree = map.get(nums[i])[0]; min = i - map.get(nums[i])[1] + 1; } else if (degree == map.get(nums[i])[0]) { min = Math.min(min, i - map.get(nums[i])[1] + 1); } } return min; }
05 第四種解法
我們也可以使用兩個HashMap,而不使用陣列。第一個HashMap的value存每個元素出現的次數,第二個HashMap的value存每個元素出現的初始位置索引。
在迴圈中,每次去比較第一個HashMap的value,如果比degree大,就更新degree的值,同時算出該元素起始索引和結束索引之間的距離;如果和degree相等,就在兩者之間取較小值。
public int findShortestSubArray4(int[] nums) { if (nums == null || nums.length == 0) { return 0; } int degree = 0; int min = Integer.MAX_VALUE; Map<Integer, Integer> map = new HashMap<Integer, Integer>(); Map<Integer, Integer> map2 = new HashMap<Integer, Integer>(); for (int i=0; i<nums.length; i++) { map.put(nums[i], map.getOrDefault(nums[i], 0)+1); if (!map2.containsKey(nums[i])) { map2.put(nums[i], i); } if (degree < map.get(nums[i])) { degree = map.get(nums[i]); min = i - map2.get(nums[i]) + 1; } else if (degree == map.get(nums[i])) { min = Math.min(min, i - map2.get(nums[i]) + 1); } } return min; }
06 小結
演算法專題目前已日更超過四個月 ,演算法題文章162 +篇,公眾號對話方塊回覆【資料結構與演算法 】、【演算法 】、【資料結構 】中的任一關鍵詞,獲取系列文章合集。
以上就是全部內容,如果大家有什麼好的解法思路、建議或者其他問題,可以下方留言交流,點贊、留言、轉發就是對我最大的回報和支援!