[LeetCode] Degree of an Array 数组的度

简介:

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的数字不一定只有一个,我们遍历所有的,找出其中最小的即可,参见代码如下:

解法一:

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也更新为当前数字出现的次数。参见代码如下: 

解法二:

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;
    }
};

参考资料:

https://discuss.leetcode.com/topic/107097/java-o-n-time-o-n-space

https://discuss.leetcode.com/topic/107216/concise-c-solution-using-hash-map-o-n-time

本文转自博客园Grandyang的博客,原文链接:[LeetCode] Degree of an Array 数组的度

,如需转载请自行联系原博主。

相关文章
|
Go
【LeetCode 热题100】DP 实战进阶:最长递增子序列、乘积最大子数组、分割等和子集(力扣300 / 152/ 416 )(Go语言版)
本文深入解析三道经典的动态规划问题:**最长递增子序列(LIS)**、**乘积最大子数组** 和 **分割等和子集**。 - **300. LIS** 通过 `dp[i]` 表示以第 `i` 个元素结尾的最长递增子序列长度,支持 O(n²) 动态规划与 O(n log n) 的二分优化。 - **152. 乘积最大子数组** 利用正负数特性,同时维护最大值与最小值的状态转移方程。 - **416. 分割等和子集** 转化为 0-1 背包问题,通过布尔型 DP 实现子集和判断。 总结对比了三题的状态定义与解法技巧,并延伸至相关变种问题,助你掌握动态规划的核心思想与灵活应用!
489 1
|
11月前
|
测试技术 PHP 开发者
PHP 数组查找:为什么 `isset()` 比 `in_array()` 快得多?
PHP 数组查找:为什么 `isset()` 比 `in_array()` 快得多?
|
人工智能 Java
Java 中数组Array和列表List的转换
本文介绍了数组与列表之间的相互转换方法,主要包括三部分:1)使用`Collections.addAll()`方法将数组转为列表,适用于引用类型,效率较高;2)通过`new ArrayList&lt;&gt;()`构造器结合`Arrays.asList()`实现类似功能;3)利用JDK8的`Stream`流式计算,支持基本数据类型数组的转换。此外,还详细讲解了列表转数组的方法,如借助`Stream`实现不同类型数组间的转换,并附带代码示例与执行结果,帮助读者深入理解两种数据结构的互转技巧。
1037 1
Java 中数组Array和列表List的转换
|
存储 Go 索引
go语言中的数组(Array)
go语言中的数组(Array)
382 67
|
JavaScript 前端开发 API
JavaScript中通过array.map()实现数据转换、创建派生数组、异步数据流处理、复杂API请求、DOM操作、搜索和过滤等,array.map()的使用详解(附实际应用代码)
array.map()可以用来数据转换、创建派生数组、应用函数、链式调用、异步数据流处理、复杂API请求梳理、提供DOM操作、用来搜索和过滤等,比for好用太多了,主要是写法简单,并且非常直观,并且能提升代码的可读性,也就提升了Long Term代码的可维护性。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
移动开发 运维 供应链
通过array.some()实现权限检查、表单验证、库存管理、内容审查和数据处理;js数组元素检查的方法,some()的使用详解,array.some与array.every的区别(附实际应用代码)
array.some()可以用来权限检查、表单验证、库存管理、内容审查和数据处理等数据校验工作,核心在于利用其短路机制,速度更快,节约性能。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
供应链 JavaScript 前端开发
通过array.every()实现数据验证、权限检查和一致性检查;js数组元素检查的方法,every()的使用详解,array.some与array.every的区别(附实际应用代码)
array.every()可以用来数据验证、权限检查、一致性检查等数据校验工作,核心在于利用其短路机制,速度更快,节约性能。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
Web App开发 存储 前端开发
别再用双层遍历循环来做新旧数组对比,寻找新增元素了!使用array.includes和Set来提升代码可读性
这类问题的重点在于能不能突破基础思路,突破基础思路是从程序员入门变成中级甚至高级的第一步,如果所有需求都通过最基础的业务逻辑来做,是得不到成长的。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
数据采集 JavaScript 前端开发
JavaScript中通过array.filter()实现数组的数据筛选、数据清洗和链式调用,JS中数组过滤器的使用详解(附实际应用代码)
用array.filter()来实现数据筛选、数据清洗和链式调用,相对于for循环更加清晰,语义化强,能显著提升代码的可读性和可维护性。博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
人工智能 前端开发 JavaScript
拿下奇怪的前端报错(一):报错信息是一个看不懂的数字数组Buffer(475) [Uint8Array],让AI大模型帮忙解析
本文介绍了前端开发中遇到的奇怪报错问题,特别是当错误信息不明确时的处理方法。作者分享了自己通过还原代码、试错等方式解决问题的经验,并以一个Vue3+TypeScript项目的构建失败为例,详细解析了如何从错误信息中定位问题,最终通过解读错误信息中的ASCII码找到了具体的错误文件。文章强调了基础知识的重要性,并鼓励读者遇到类似问题时不要慌张,耐心分析。
814 5

热门文章

最新文章