array专题3-一道题目不断分析就会慢慢有了思路
#697 Degree of an Array
我承認慢慢有了思路的前提是你要見過那些解法,否則怎么想也想不到。多做題目,就像是多看書一樣重要。
問題:一個數組的度=這個數組中出現次數最多元素的出現次數。要找的是最短的子數組,而這個數組的度=原數組的度。
思路一:我肯定需要一次循環,找到數組的度;接著計算每個子數組,計算它們的度,找到和原數組的度相同的最短的子數組。每個子數組就是從下標0開始的子數組,從下標1開始的子數組…。所以有了如下代碼。代碼時間復雜度O(n^2),發生TLE。
思路二:需要把兩層循環改為1層。觀察例子中給出的子數組:[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接著再循環找到這個度是由哪個元素貢獻的。例如數組 [1, 2, 2, 3, 1]的度是2,是由元素2貢獻的。找到2這個元素;
3最后要循環找到這個元素的起止位置,計算子數組的長度。
所以有了如下代碼。注意的是:出現次數最多的元素可能不止一個。
思路三:上面的三步有沒有可以合并的呢?是不是可以在計算數組的度的時候,順便記錄下每個元素的起止位置呢?當然可以。第二步尋找出現次數等于數組度的元素,和計算子數組長度放在一起。于是有了以下代碼。
public int findShortestSubArrayV3(int[] nums) {Map<Integer, Integer> countMap = new HashMap<Integer, Integer>();Map<Integer, Integer[]> numIndexMap = new HashMap<Integer, Integer[]>();int degree = 0;for (int i = 0; i < nums.length; i++) {int num = nums[i];if (countMap.get(num) == null) {countMap.put(num, 1);} else {countMap.put(num, 1 + countMap.get(num));}degree = Math.max(degree, countMap.get(num));if(numIndexMap.get(num)==null){numIndexMap.put(num, new Integer[]{i,i});}else{numIndexMap.get(num)[1] = i;}}int minLength = nums.length;for(int num : countMap.keySet()){if(countMap.get(num) == degree){minLength = Math.min(minLength, numIndexMap.get(num)[1] - numIndexMap.get(num)[0]+1);}}return minLength;} 一步一步改進自己的思路。從最直覺入手。改進的依據是觀察標準答案的特征;縮短使用時間。思路四:看了discuss。兩個map合并為一個map,先準備基礎數據再計算。不得不說,作者真是牛。作者代碼更注重的細節是:Map<Integer,int[]>numMapMap<Integer, int[]> numMapMap<Integer,int[]>numMap 而不是$ Map<Integer, Integer[]> numMap $,我試過了,速度更快。map的get方法盡量調用一次(看我上面代碼就知道,我不是這樣做的)。作者在最后遍歷的是numMap.values(),速度更快。
public int findShortestSubArrayV4(int[] nums) {if (nums.length == 0 || nums == null) return 0;Map<Integer, int[]> numMap = new HashMap<Integer, int[]>();for (int i = 0; i < nums.length; i++) {int num = nums[i];if (numMap.get(num) == null) {numMap.put(num, new int[]{1,i,i});} else {int[] temp = numMap.get(num);temp[0]++;temp[2]=i;}}int degree = 0;int minLength = nums.length;for(int[] values : numMap.values()){if(degree < values[0]){degree = values[0];minLength = values[2]-values[1] +1;}else if(degree == values[0]){minLength = Math.min(minLength, values[2]-values[1] +1);}}return minLength;}思路5:第二遍刷題。觀察到了需要找到出現最多次數元素最左邊、最右邊的位置。
public int findShortestSubArray(int[] nums) {Map<Integer,Integer> left = new HashMap<Integer,Integer>();Map<Integer,Integer> right = new HashMap<Integer,Integer>();Map<Integer,Integer> count = new HashMap<Integer,Integer>();int degree = 0; for(int i=0;i<nums.length;i++){if(left.get(nums[i])==null) left.put(nums[i],i);right.put(nums[i],i);if(count.get(nums[i])==null)count.put(nums[i],1);elsecount.put(nums[i],count.get(nums[i])+1);degree = Math.max(degree,count.get(nums[i]));}int answer = nums.length;for(Integer num : left.keySet()){if(count.get(num)==degree){answer = Math.min(answer,right.get(num)-left.get(num)+1);}}return answer;}總結
以上是生活随笔為你收集整理的array专题3-一道题目不断分析就会慢慢有了思路的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微服务扩展新途径:Messaging
- 下一篇: Linux 路径和目录问题