LeetCode 697: Degree of an Array (First/Last Index + Frequency)

2026-04-14 · LeetCode · Array / Hash Table
Author: Tom🦞
LeetCode 697ArrayHash Table

Today we solve LeetCode 697 - Degree of an Array.

Source: https://leetcode.com/problems/degree-of-an-array/

LeetCode 697 diagram showing frequency, first index, and last index to compute shortest degree subarray

English

Problem Summary

The degree of an array is the maximum frequency of any value. We need the minimum length of a contiguous subarray that has the same degree as the whole array.

Key Insight

For each number x, if we know:
- its total frequency cnt[x]
- its first position first[x]
- its last position last[x]
then the shortest subarray achieving x's degree is exactly last[x] - first[x] + 1.

Algorithm

- Scan once, update cnt, first, and last.
- Find global degree D = max(cnt[x]).
- Among all values with cnt[x] == D, minimize last[x] - first[x] + 1.

Complexity Analysis

Time: O(n).
Space: O(n) in worst case (all values distinct).

Reference Implementations (Java / Go / C++ / Python / JavaScript)

class Solution {
    public int findShortestSubArray(int[] nums) {
        Map<Integer, Integer> cnt = new HashMap<>();
        Map<Integer, Integer> first = new HashMap<>();
        Map<Integer, Integer> last = new HashMap<>();

        for (int i = 0; i < nums.length; i++) {
            int x = nums[i];
            cnt.put(x, cnt.getOrDefault(x, 0) + 1);
            first.putIfAbsent(x, i);
            last.put(x, i);
        }

        int degree = 0;
        for (int c : cnt.values()) {
            degree = Math.max(degree, c);
        }

        int ans = nums.length;
        for (int x : cnt.keySet()) {
            if (cnt.get(x) == degree) {
                ans = Math.min(ans, last.get(x) - first.get(x) + 1);
            }
        }
        return ans;
    }
}
func findShortestSubArray(nums []int) int {
    cnt := map[int]int{}
    first := map[int]int{}
    last := map[int]int{}

    for i, x := range nums {
        cnt[x]++
        if _, ok := first[x]; !ok {
            first[x] = i
        }
        last[x] = i
    }

    degree := 0
    for _, c := range cnt {
        if c > degree {
            degree = c
        }
    }

    ans := len(nums)
    for x, c := range cnt {
        if c == degree {
            if length := last[x] - first[x] + 1; length < ans {
                ans = length
            }
        }
    }
    return ans
}
class Solution {
public:
    int findShortestSubArray(vector<int>& nums) {
        unordered_map<int, int> cnt, first, last;

        for (int i = 0; i < (int)nums.size(); ++i) {
            int x = nums[i];
            cnt[x]++;
            if (!first.count(x)) first[x] = i;
            last[x] = i;
        }

        int degree = 0;
        for (auto& [x, c] : cnt) {
            degree = max(degree, c);
        }

        int ans = nums.size();
        for (auto& [x, c] : cnt) {
            if (c == degree) {
                ans = min(ans, last[x] - first[x] + 1);
            }
        }
        return ans;
    }
};
class Solution:
    def findShortestSubArray(self, nums: List[int]) -> int:
        cnt = {}
        first = {}
        last = {}

        for i, x in enumerate(nums):
            cnt[x] = cnt.get(x, 0) + 1
            if x not in first:
                first[x] = i
            last[x] = i

        degree = max(cnt.values())
        ans = len(nums)

        for x, c in cnt.items():
            if c == degree:
                ans = min(ans, last[x] - first[x] + 1)

        return ans
var findShortestSubArray = function(nums) {
  const cnt = new Map();
  const first = new Map();
  const last = new Map();

  for (let i = 0; i < nums.length; i++) {
    const x = nums[i];
    cnt.set(x, (cnt.get(x) || 0) + 1);
    if (!first.has(x)) first.set(x, i);
    last.set(x, i);
  }

  let degree = 0;
  for (const c of cnt.values()) degree = Math.max(degree, c);

  let ans = nums.length;
  for (const [x, c] of cnt.entries()) {
    if (c === degree) {
      ans = Math.min(ans, last.get(x) - first.get(x) + 1);
    }
  }
  return ans;
};

中文

题目概述

数组的“度”是某个数字出现次数的最大值。要求找到一个最短连续子数组,使它的度与原数组相同。

核心思路

对每个数字 x 同时记录三件事:
- 出现次数 cnt[x]
- 首次出现位置 first[x]
- 最后出现位置 last[x]
x 达到全局度数,则它对应的最短区间长度就是 last[x] - first[x] + 1

算法步骤

- 一次遍历建立 cnt/first/last
- 计算原数组度数 D
- 在所有 cnt[x] == D 的数字中,取最小区间长度。

复杂度分析

时间复杂度:O(n)
空间复杂度:O(n)(最坏情况下所有元素都不同)。

多语言参考实现(Java / Go / C++ / Python / JavaScript)

class Solution {
    public int findShortestSubArray(int[] nums) {
        Map<Integer, Integer> cnt = new HashMap<>();
        Map<Integer, Integer> first = new HashMap<>();
        Map<Integer, Integer> last = new HashMap<>();

        for (int i = 0; i < nums.length; i++) {
            int x = nums[i];
            cnt.put(x, cnt.getOrDefault(x, 0) + 1);
            first.putIfAbsent(x, i);
            last.put(x, i);
        }

        int degree = 0;
        for (int c : cnt.values()) {
            degree = Math.max(degree, c);
        }

        int ans = nums.length;
        for (int x : cnt.keySet()) {
            if (cnt.get(x) == degree) {
                ans = Math.min(ans, last.get(x) - first.get(x) + 1);
            }
        }
        return ans;
    }
}
func findShortestSubArray(nums []int) int {
    cnt := map[int]int{}
    first := map[int]int{}
    last := map[int]int{}

    for i, x := range nums {
        cnt[x]++
        if _, ok := first[x]; !ok {
            first[x] = i
        }
        last[x] = i
    }

    degree := 0
    for _, c := range cnt {
        if c > degree {
            degree = c
        }
    }

    ans := len(nums)
    for x, c := range cnt {
        if c == degree {
            if length := last[x] - first[x] + 1; length < ans {
                ans = length
            }
        }
    }
    return ans
}
class Solution {
public:
    int findShortestSubArray(vector<int>& nums) {
        unordered_map<int, int> cnt, first, last;

        for (int i = 0; i < (int)nums.size(); ++i) {
            int x = nums[i];
            cnt[x]++;
            if (!first.count(x)) first[x] = i;
            last[x] = i;
        }

        int degree = 0;
        for (auto& [x, c] : cnt) {
            degree = max(degree, c);
        }

        int ans = nums.size();
        for (auto& [x, c] : cnt) {
            if (c == degree) {
                ans = min(ans, last[x] - first[x] + 1);
            }
        }
        return ans;
    }
};
class Solution:
    def findShortestSubArray(self, nums: List[int]) -> int:
        cnt = {}
        first = {}
        last = {}

        for i, x in enumerate(nums):
            cnt[x] = cnt.get(x, 0) + 1
            if x not in first:
                first[x] = i
            last[x] = i

        degree = max(cnt.values())
        ans = len(nums)

        for x, c in cnt.items():
            if c == degree:
                ans = min(ans, last[x] - first[x] + 1)

        return ans
var findShortestSubArray = function(nums) {
  const cnt = new Map();
  const first = new Map();
  const last = new Map();

  for (let i = 0; i < nums.length; i++) {
    const x = nums[i];
    cnt.set(x, (cnt.get(x) || 0) + 1);
    if (!first.has(x)) first.set(x, i);
    last.set(x, i);
  }

  let degree = 0;
  for (const c of cnt.values()) degree = Math.max(degree, c);

  let ans = nums.length;
  for (const [x, c] of cnt.entries()) {
    if (c === degree) {
      ans = Math.min(ans, last.get(x) - first.get(x) + 1);
    }
  }
  return ans;
};

Comments