[LeetCode]697. Degree of an Array 解题报告(C++)

[LeetCode]697. Degree of an Array 解题报告(C++)

题目描述

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.

题目大意

  • 给定一个非空非负的数组, 数组的度定义为: 某个元素出现的最大次数.
  • 要求找到一个 长度最小的连续子串! 和给定数组的度相同.

解题思路

方法1:

  • 暴力方法:
  • 通过哈希表来存储 两个关系!
    1. 数字的次数的关系
    2. 数字和 {起始,结束位置}的关系
  • 由于这个题目要求最小.将这些信息都记录下来.
  • 最后遍历 找到出现出现次数最多的数字(可能多个)
  • 再比较找到最小长度

代码实现:

class Solution0 {
public:
    int findShortestSubArray(vector<int>& nums) {
        unordered_map<int, int> m;
        unordered_map<int, pair<int, int>> pos;

        int degree = 0;
        for (int i = 0; i < nums.size(); i++) {
            // 该数字第一次出现,记录下起始位置.
            if (++m[nums[i]] == 1) {
                pos[nums[i]] = { i,i };
            }
            else { // 该数字出现不止一次.改变右边界.
                pos[nums[i]].second = i;
            }
            // 更新最大的次数
            degree = max(degree, m[nums[i]]);
        }

        int res = INT_MAX;

        for (auto x : m) {
            // 找到出现最多的数字. x.first 通过first 找到其左右边界.
            if (x.second == degree) {
                res = min(pos[x.first].second - pos[x.first].first + 1,res);
            }
        }
        return res;

    }
};

方法2:

  • 优化算法. 只需要遍历一次数组
  • 1 建立每个数字出现次数的哈希表. 2 建立每个数字起始位置的表.
  • 在遍历过程中.
  • 累计当前数字的出现次数.
  • 若某个数字第一个出现,则建立数字与起始位置的映射关系.
  • 当前数字的出现次数等于 degree .则更新 res (计算这个数字出现位置到当前的长度与 res比较大小,取消的)
  • 当前数字的出现次数大于 degree .则需要更改当前数字左右边界长度作为res.并且更新degree.

代码实现:

class Solution {
public:
    int findShortestSubArray(vector<int>& nums) {
        int size = nums.size();
        int res = INT_MAX;
        int degree = 0;

        unordered_map<int, int> m, startIdx;

        for (int i = 0; i < size; i++) {
            m[nums[i]]++; // 次数更新
            if (m[nums[i]] == 1) {
                // 第一次出现,建立起始位置和数字的映射
                startIdx[nums[i]] = i;
            }
            if(m[nums[i]]==degree) {
                // 等于degree,则得到了最远的距离
                // 则需要计算最小的长度
                res = min(res,i - startIdx[nums[i]] + 1);
            }
            else if(m[nums[i]]>degree) {
                // 出现次数更多.则需要更新 res成为最高次数对应的长度;
                res = i - startIdx[nums[i]] + 1;
                degree = m[nums[i]];
            }
        }
        return res;
    }
};

小结

  • 理解题目的意思很重要!!! 需要建立哪些关系!!!
  • 哈希表真的很有用!!!

猜你喜欢

转载自blog.csdn.net/qjh5606/article/details/81382710