Degree of an Array LT697

Given a non-empty array of non-negative integers nums, the degree of this array is defined as the maximum frequency of any one of its elements.

Your task is to find the smallest possible length of a (contiguous) subarray of nums, that has the same degree as nums.

Example 1:

Input: [1, 2, 2, 3, 1]
Output: 2
Explanation: 
The input array has a degree of 2 because both elements 1 and 2 appear twice.
Of the subarrays that have the same degree:
[1, 2, 2, 3, 1], [1, 2, 2, 3], [2, 2, 3, 1], [1, 2, 2], [2, 2, 3], [2, 2]
The shortest length is 2. So return 2.

 

Example 2:

Input: [1,2,2,3,1,4,2]
Output: 6

Note:

    • nums.length will be between 1 and 50,000.
    • nums[i] will be an integer between 0 and 49,999.

 Idea 1. Scan the array to build the frequency map, store the pair(nums[i], frequency), find out the max frequecy = degree, find out all candidates have the degree, build a second map with position to store the pari(nums[i], {start, end}}, loop the second map to find the max length end - start + 1.

Time complexity: O(N)

Space complexity: O(M) - unieque numbers in the array, could be O(N) if the degree is 1.

 1 class Solution {
 2     public int findShortestSubArray(int[] nums) {
 3         Map<Integer, Integer> frequency = new HashMap<>();
 4         for(int num: nums) {
 5            frequency.put(num, frequency.getOrDefault(num, 0) + 1);
 6         }
 7         
 8         int degree = 0;
 9         for(int val: frequency.values()) {
10            degree = Math.max(degree, val);
11         }
12         
13         Set<Integer> candidates = new HashSet<>();
14         for(int key: frequency.keySet()) {
15             if(frequency.get(key) == degree) {
16                 candidates.add(key);
17             }
18         }
19         
20         Map<Integer, List<Integer>> start = new HashMap<>();
21         for(int i = 0; i < nums.length; ++i) {
22             if(candidates.contains(nums[i])) {
23                 start.putIfAbsent(nums[i], Arrays.asList(i, i));
24                 List<Integer> pos = start.get(nums[i]);
25                 pos.set(1, i);
26             }
27         }
28         
29         int result = nums.length;
30         for(List<Integer> pos: start.values()) {
31             result = Math.min(result, pos.get(1) - pos.get(0) + 1);
32         }
33         
34         return result;
35     }
36 }

Let's start refactoring the code:

1. get the degree while building frequency map, saving the loop

2. save the start position of each number in start map, update the length as loop the array, note: each number could be the candidate, not just the number currently having same degree, as the counter could be increased as the same number occurs later

Time complexity: O(N), 1 scan only

Space complexity: O(M)

 1 class Solution {
 2     public int findShortestSubArray(int[] nums) {
 3         int degree = 0;
 4         int result = nums.length;
 5         Map<Integer, Integer> frequency = new HashMap<>();
 6         Map<Integer, Integer> start = new HashMap<>();
 7         
 8         for(int i = 0; i < nums.length; ++i) {
 9            frequency.put(nums[i], frequency.getOrDefault(nums[i], 0) + 1);
10            start.putIfAbsent(nums[i], i);
11            if(frequency.get(nums[i]) > degree) {
12                degree = frequency.get(nums[i]);
13                result = i - start.get(nums[i]) + 1;
14            }
15            else if(frequency.get(nums[i])  == degree) {
16                 result = Math.min(result, i - start.get(nums[i]) + 1);
17             }
18         }
19         
20         return result;
21     }
22 }

 

posted on 2019-05-09 09:53  一直走在路上  阅读(84)  评论(0编辑  收藏  举报

导航