697 degree of an array

本文介绍了一种算法,用于在给定的非空整数数组中找到具有与原数组相同度的最短连续子数组。度被定义为数组中任何一个元素的最大频率。通过使用哈希表来跟踪每个元素的出现次数及其首次和最后一次出现的位置,算法能够有效地解决这个问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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.

 

这道题给了我们一个数组,定义数组的度为某个或某些数字出现最多的次数,要我们找最短的子数组使其和原数组拥有相同的度。那么肯定需要统计每个数字出现的次数,就要用哈希表来建立每个数字和其出现次数之间的映射。由于我们要求包含原度的最小长度的子数组,那么最好的情况就是子数组的首位数字都是统计度的数字,即出现最多的数字。那么肯定要知道该数字的第一次出现的位置和最后一次出现的位置,由于我们开始不知道哪些数字会出现最多次,所以我们统计所有数字的首尾出现位置,那么再用一个哈希表,建立每个数字和其首尾出现的位置。我们用变量degree来表示数组的度。遍历原数组,累加当前数字出现的次数,当某个数字是第一次出现,那么我们用当前位置的来更新该数字出现的首尾位置,否则只更新尾位置。每遍历一个数,都更新一下degree。当遍历完成后,我们已经有了数组的度,还有每个数字首尾出现的位置,下面就来找出现次数为degree的数组,然后计算其首尾位置差加1就是candidate数组的长度,由于出现次数为degree的数字不一定只有一个,我们遍历所有的,找出其中最小的即可:

 

解法一:

class Solution {

public:

    int findShortestSubArray(vector<int>& nums) {

        int n = nums.size(), res = INT_MAX, degree = 0;

        unordered_map<int, int> m;

        unordered_map<int, pair<int, int>> pos;

        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]]);

        }

        for (auto a : m) {

            if (degree == a.second) {

                res = min(res, pos[a.first].second - pos[a.first].first + 1);

            }

        }

        return res;

    }

};

下面这种方法只用了一次遍历,思路跟上面的解法很相似,还是要建立数字出现次数的哈希表,还有就是建立每个数字和其第一次出现位置之间的映射,那么我们当前遍历的位置其实可以看作是尾位置,还是可以计算子数组的长度的。我们遍历数组,累加当前数字出现的次数,如果某个数字是第一次出现,建立该数字和当前位置的映射,如果当前数字的出现次数等于degree时,当前位置为尾位置,首位置在startIdx中取的,二者做差加1来更新结果res;如果当前数字的出现次数大于degree,说明之前的结果代表的数字不是出现最多的,直接将结果res更新为当前数字的首尾差加1的长度,然后degree也更新为当前数字出现的次数。

 

解法二:

class Solution {

public:

    int findShortestSubArray(vector<int>& nums) {

        int n = nums.size(), res = INT_MAX, degree = 0;

        unordered_map<int, int> m, startIdx;

        for (int i = 0; i < n; ++i) {

            ++m[nums[i]];

            if (!startIdx.count(nums[i])) startIdx[nums[i]] = i;

            if (m[nums[i]] == degree) {

                res = min(res, i - startIdx[nums[i]] + 1);

            } else if (m[nums[i]] > degree) {

                res = i - startIdx[nums[i]] + 1;

                degree = m[nums[i]];

            }

        }

        return res;

    }

};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值