array专题3-一道题目不断分析就会慢慢有了思路
#697 Degree of an Array
我承認(rèn)慢慢有了思路的前提是你要見過那些解法,否則怎么想也想不到。多做題目,就像是多看書一樣重要。
問題:一個數(shù)組的度=這個數(shù)組中出現(xiàn)次數(shù)最多元素的出現(xiàn)次數(shù)。要找的是最短的子數(shù)組,而這個數(shù)組的度=原數(shù)組的度。
思路一:我肯定需要一次循環(huán),找到數(shù)組的度;接著計算每個子數(shù)組,計算它們的度,找到和原數(shù)組的度相同的最短的子數(shù)組。每個子數(shù)組就是從下標(biāo)0開始的子數(shù)組,從下標(biāo)1開始的子數(shù)組…。所以有了如下代碼。代碼時間復(fù)雜度O(n^2),發(fā)生TLE。
思路二:需要把兩層循環(huán)改為1層。觀察例子中給出的子數(shù)組:[1, 2, 2, 3, 1], [1, 2, 2, 3], [2, 2, 3, 1], [1, 2, 2], [2, 2, 3], [2, 2],符合條件的是[2,2]。既然數(shù)組的度是由出現(xiàn)次數(shù)最多的元素的頻次貢獻(xiàn)的,那子數(shù)組中肯定包含這個元素。要求最短,那子數(shù)組的起始元素和結(jié)束元素肯定都是這個元素。所以思路改為:
1 需要一次循環(huán),找到數(shù)組的度;
2接著再循環(huán)找到這個度是由哪個元素貢獻(xiàn)的。例如數(shù)組 [1, 2, 2, 3, 1]的度是2,是由元素2貢獻(xiàn)的。找到2這個元素;
3最后要循環(huán)找到這個元素的起止位置,計算子數(shù)組的長度。
所以有了如下代碼。注意的是:出現(xiàn)次數(shù)最多的元素可能不止一個。
思路三:上面的三步有沒有可以合并的呢?是不是可以在計算數(shù)組的度的時候,順便記錄下每個元素的起止位置呢?當(dāng)然可以。第二步尋找出現(xiàn)次數(shù)等于數(shù)組度的元素,和計算子數(shù)組長度放在一起。于是有了以下代碼。
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;} 一步一步改進(jìn)自己的思路。從最直覺入手。改進(jìn)的依據(jù)是觀察標(biāo)準(zhǔn)答案的特征;縮短使用時間。思路四:看了discuss。兩個map合并為一個map,先準(zhǔn)備基礎(chǔ)數(shù)據(jù)再計算。不得不說,作者真是牛。作者代碼更注重的細(xì)節(jié)是:Map<Integer,int[]>numMapMap<Integer, int[]> numMapMap<Integer,int[]>numMap 而不是$ Map<Integer, Integer[]> numMap $,我試過了,速度更快。map的get方法盡量調(diào)用一次(看我上面代碼就知道,我不是這樣做的)。作者在最后遍歷的是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:第二遍刷題。觀察到了需要找到出現(xiàn)最多次數(shù)元素最左邊、最右邊的位置。
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;}總結(jié)
以上是生活随笔為你收集整理的array专题3-一道题目不断分析就会慢慢有了思路的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微服务扩展新途径:Messaging
- 下一篇: 花花酱leetcode 题目-二分搜索