1. 统计数组中元素总结

1.1 统计元素出现的次数

为了统计元素出现的次数,我们肯定需要一个map来记录每个数组以及对应数字出现的频次。这里map的选择比较有讲究:

  1. 如果数据的范围有限制,如:只有小写字母、1000以内的正数等,这时我们可以通过一个数组来充当map
  2. 如果数据的范围没有限制,或者数据范围很大:如:int的数据范围,这时我们可以通过HashMap存储对应的keyvalue

可参考代码:

for(int i = 0; i< nums.length; i++){
count[nums[i]]++;
}

1.2 统计元素在数组中出现的最左和最右位置

首先想清楚一个问题:

  1. 从左到右遍历,最后遍历到的就是最右元素;
  2. 从右到左遍历,最后遍历到的就是最左元素;

我们就可以依据此,创建leftright变量,从左往右遍历时更新right,从右往左遍历时更新left

for(int i = 0; i < nums.length; i++){
if(nums[i] == target){
right = i;
}
} for(int i = nums.length - 1; i >= 0; i--){
if(nums[i] == target){
left = i;
}
}

1.3 统计元素有没有出现(有没有重复出现)

思路仍然是:统计元素出现的次数,最后根据count数组来判断元素是否出现或者元素是否重复出现。

有时,题目要求我们空间复杂度为O(1),这时我们要仔细地审题。挖掘统计数组与原数组之间的关系,一般情况下我们只能通过修改原数组来统计每个元素出现的次数。比如说:如果数组中元素都在[1, n]之间,而且原数组的长度也为:n,此时我们就可以通过修改原数组来记录元素出现的次数。

在这种类型的题目中,一个有用的观念是:

  1. 对于nums中的一个数据x,我们用nums[x - 1] 来标识这个元素是否已经出现过;
  2. 为了标识nums[x - 1]是否出现过,我们不能使用nums中原来就会出现的数字,比如说:范围[1, n]之间的数字;一个常用的方法是:将nums[x - 1]转化为负数,这样就可以用来标识 x 之前是否已经出现过;
for(int i = 0; i < nums.length; i++){
// 防止 x 为负数
int x = Math.abs(nums[i)); if(nums[x - 1] < 0){
// 出现过,做操作
}else{
// 通过负数来标识元素x已经出现过了
nums[x - 1] = - nums[x - 1];
}
}

2. 题目记录

645. 错误的集合

分析题意

一个长度为n的集合s中本来存储的是1-n的数据,将数据打乱后并挑选一个数据替换成1-n之间的其他数据。请你找出:被替换的数据和替换成的数据。

这道题的关键在于:数据其实是无序的,所以我们不能依靠相邻元素的大小关系来进行判断。

思路分析

如果我们能够统计数组中每个元素的出现次数,那么查到被替换的数据(频次为0),替换成的数据(频次为2)就十分的简单。

int[] count = new int[nums.length];
for(int i = 0; i < nums.length; i++){
count[nums[i] - 1] ++;
} for(int i = 0; i < count.length; i++){ if(count[i] == 0){
// 被替换的元素
} if(count[i] == 2){
// 替换的元素
}
}

我们可以发现,count的大小为n,而nums的大小也为n。那么我们能不能用nums数组来标识一个元素是否出现过呢?答案是可以的。

class Solution {
public int[] findErrorNums(int[] nums) {
int[] ans = new int[2];
for(int i = 0; i < nums.length; i++){
int k = Math.abs(nums[i]);
if(nums[k - 1] < 0){
// 前面已经出现过
ans[0] = k;
}else{
nums[k - 1] = - nums[k - 1];
}
}
// 经过上述过程
// 如果x出现,那么nums[x - 1] 为负数
// 如果x没有出现,那么nums[x - 1]保持原样不变
for(int i = 0; i < nums.length; i++){
if(nums[i] > 0){
ans[1] = i + 1;
break;
}
} return ans;
}
}

复杂度分析

时间复杂度:O(n)

空间复杂度:O(1)

697. 数组的度

分析题意

要想知道元素 从出现的最大频次,那么我们需要统计每个元素出现的次数。

要计算长度就需要知道最大出现元素的起始位置和终止位置,即元素的最左位置和最右位置。

所以,这道题就转化为了:求每个元素频次以及最左和最右位置。

思路分析

由于数据的范围较大,所以我们通过map来进行存储。

class Solution {
public int findShortestSubArray(int[] nums) {
HashMap<Integer, Integer> count = new HashMap<>();
HashMap<Integer, Integer> left = new HashMap<>();
HashMap<Integer, Integer> right = new HashMap<>(); // 统计频次和最右元素
for(int i = 0; i < nums.length; i++){
count.put(nums[i], count.getOrDefault(nums[i], 0) + 1);
right.put(nums[i], i);
}
// 统计最左元素
for(int i = nums.length - 1; i >= 0; i--){
left.put(nums[i], i);
} int maxFreq = 0;
int minLen = 0;
for(Map.Entry<Integer, Integer> entry: count.entrySet()){
if(entry.getValue() > maxFreq){
maxFreq = entry.getValue();
minLen = right.get(entry.getKey()) - left.get(entry.getKey()) + 1;
}else if(entry.getValue() == maxFreq){
minLen = Math.min(minLen, right.get(entry.getKey()) - left.get(entry.getKey()) + 1);
}
} return minLen; }
}

复杂度分析

时间复杂度:O(n)

空间复杂度:O(n)

448. 找到所有数组中消失的数字

分析题意

一个长度为n的数组内,所有数字都在1-n范围内。请找出在1-n范围内但是没有出现在数组中的元素。

思路分析

如果我们知道1-n范围内每个数字出现的频次,那么出现频次为0的所有元素都是我们想要找的元素。进一步来说,其实我们只关注这个元素是否出现过,即:>0=0的差别,不关心具体出现了几次。

题目要求我们使用常数空间复杂度来解决这道题目。那我们只能通过修改原数组来实现统计是否元素是否出现这个需求。和上面一样,我们使用 nums[x - 1]是否为负数来标识元素x是否已经出现过。

class Solution {
public List<Integer> findDisappearedNumbers(int[] nums) {
for(int i = 0; i < nums.length; i++){
int k = Math.abs(nums[i]);
// 确保将 k-1 置为负数
nums[k - 1] = - Math.abs(nums[k - 1]);
} List<Integer> ans = new ArrayList<>();
for(int i = 0; i < nums.length; i++){
if(nums[i] > 0){
ans.add(i + 1);
}
} return ans; }
}

复杂度分析

时间复杂度:O(n)

空间复杂度:O(1), 返回元素不计算

442. 数组中重复的数据

分析题意

长度为n的数组中,每个元素都在1-n范围内,且每个元素要么出现1次,要么出现2次,(其实隐含着:1-n内的有些元素并不在数组中,因为存在重复元素)找出所有出现2次的元素。

要求:时间复杂为O(n),空间复杂度为O(1)

思路分析

如果我们能用一个集合存储已经出现过的元素,然后每次遍历一个新元素时先判断该元素是否在已有的集合中:

  1. 如果已经存在那么它就是我们要找的重复元素,将该元素加入到结果集中;
  2. 如果不存在那么就把它加入到集合中;
for(int i = 0; i < nums.length; i++){
// 如果set中没有该元素,添加成功返回true
// 如果set中存在该元素,添加失败返回false
if(!set.add(nums[i]){
ans.add(nums[i]);
} }

上述方法的时间复杂度为O(n),但是空间复杂度也是O(n),不符合要求。那么 我们是否有办法降低时间复杂度呢?

由于数组的长度是n,数组中每一个数字都在1-n范围内,所以我们可以用nums[x - 1] 来标识元素 x 的状态:是否已经出现过,这样我们就可以实现O(1)空间复杂度了。

class Solution {
public List<Integer> findDuplicates(int[] nums) {
List<Integer> ans = new ArrayList<>();
for(int i = 0; i < nums.length; i++){
int k = Math.abs(nums[i]);
if(nums[k - 1] < 0){
// 已经出现过,这一次是第二次出现
ans.add(k);
}else{
nums[k - 1] = - nums[k - 1];
} } return ans;
}
}

复杂度分析

时间复杂度:O(n)

空间复杂度:O(1)

41. 缺失的第一个正数

分析题意

给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数

请你实现时间复杂度为O(n)并且只使用常数级别额外空间的解决方案。

对于一个长度为n的数组,其中没有出现的最小正整数的范围一定在:1~(n+1)范围内。所以我们关注的数据只有1~(n+1)中每个数的出现频次。

思路分析

题意中我们已经明白了:统计1~(n+1)中每个元素的出现频次,其实我们只统计1~n就可以了。如果1~n都出现了,那么最小的正整数就是n+1

统计1~n每个元素出现频次,那么我们需要一个长度为n的数组,这样的话空间复杂度就是O(n),不符合题意。那我们就只能从修改原数组下手了。

还记得之前的题目,我们都是通过nums[x - 1]来标识元素x是否出现过,这道题依旧适用,但是要做一点点修改。因为我们需要用负数标识元素已经出现过,但是原数组中的数据的范围是 \([-2^{(31)}, 2^{31}-1]\)存在负数,所以我们需要先将超出1~n范围内的数组全部置为n+1

class Solution {
public int firstMissingPositive(int[] nums) {
for(int i = 0; i < nums.length; i++){
if(nums[i] > nums.length || nums[i] <= 0){
nums[i] = nums.length + 1;
}
} for(int i = 0; i < nums.length; i++){
int k = Math.abs(nums[i]);
if( k <= nums.length){
nums[k - 1] = - Math.abs(nums[k - 1]);
}
} int ans = nums.length + 1;
for(int i = 0; i < nums.length; i++){
if(nums[i] >= 0){
ans = i+1;
break;
}
} return ans;
}
}

复杂度分析

时间复杂度:O(n)

空间复杂度:O(1)

LeetCode - 统计数组中的元素的更多相关文章

  1. 统计数组中各个元素出现的次数,元素取值范围为:1到N

     问题描述: * 给定一个整数数组a,长度为N,元素取值范围为[1,N]. * 统计各个元素出现的次数,要求时间复杂度为O(N),空间复杂度为O(1). * 可以改变原来数组结构.  思路: * 从第 ...

  2. [LeetCode]1464. 数组中两元素的最大乘积

    给你一个整数数组 nums,请你选择数组的两个不同下标 i 和 j,使 (nums[i]-1)*(nums[j]-1) 取得最大值. 请你计算并返回该式的最大值. 示例 1: 输入:nums = [3 ...

  3. 统计js数组中奇数元素的个数

    如何统计一个JS数组中奇数元素的个数呢? 这是群友提出的一个问题,大部分群友给出的是遍历 然后对2取模,得到最终结果. 这样的写法是最容易想得到的,那么有没有其他思路呢? 这里我提供另外一种思路,我们 ...

  4. LeetCode 27 Remove Element (移除数组中指定元素)

    题目链接: https://leetcode.com/problems/remove-element/?tab=Description   Problem : 移除数组中给定target的元素,返回剩 ...

  5. LeetCode:数组中的第K个最大元素【215】

    LeetCode:数组中的第K个最大元素[215] 题目描述 在未排序的数组中找到第 k 个最大的元素.请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素. 示例 1: ...

  6. Leetcode算法【34在排序数组中查找元素】

    在之前ARTS打卡中,我每次都把算法.英文文档.技巧都写在一个文章里,这样对我的帮助是挺大的,但是可能给读者来说,一下子有这么多的输入,还是需要长时间的消化. 那我现在改变下方式,将每一个模块细分化, ...

  7. Java实现 LeetCode 34 在排序数组中查找元素的第一个和最后一个位置

    在排序数组中查找元素的第一个和最后一个位置 给定一个按照升序排列的整数数组 nums,和一个目标值 target.找出给定目标值在数组中的开始位置和结束位置. 你的算法时间复杂度必须是 O(log n ...

  8. 【LeetCode每天一题】Find First and Last Position of Element in Sorted Array(找到排序数组中指定元素的开始和结束下标)

    Given an array of integers nums sorted in ascending order, find the starting and ending position of ...

  9. Leetcode题目34.在排序数组中查找元素的第一个和最后一个位置(中等)

    题目描述: 给定一个按照升序排列的整数数组 nums,和一个目标值 target.找出给定目标值在数组中的开始位置和结束位置. 你的算法时间复杂度必须是 O(log n) 级别. 如果数组中不存在目标 ...

随机推荐

  1. java发送http请求get/post

    1,导入依赖 <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId> ...

  2. C#通过完整的例子,Get常用的2个套路,理解抽象方法,虚方法,接口,事件

    一.理解:抽象方法,虚方法,接口,事件 描述: 1.定义一个抽象父类"People": 要求: 1>3个属性:名字,性别,年龄: 2>一个普通方法"说话&qu ...

  3. 定时脚本删除docker容器中内容

    今天在我同步mongo数据库的时候,服务器的磁盘突然就被占满了导致同步中断,mongo容器也停止工作了.然后就想要弄一个能够定时清理同步过程中留存在docker容器中的mongo数据的脚本.话不多说, ...

  4. CMake教程——Leeds_Garden

    本系列适合 乐于学习新知识的人 想要深入学习C++的人 赞美作者的人 系列目录 初步入门 基本操作 (更新中) 创作不易,欢迎分享,把知识分享给更多有需要的人.

  5. CodeTON Round 2 (Div. 1 + Div. 2, Rated, Prizes!) A-E

    比赛链接 A 题解 知识点:思维,模拟. 发现 \(b\) 串第一个字符是 \(1\) 则只能使用 max , \(0\) 则只能使用 min ,随后只需要模拟到 \(a\) 串剩余 \(m\) 个字 ...

  6. 【FAQ】【Push Kit】 华为怎么设置角标

    ​[问题描述] HMS Core Push 怎么设置角标?角标设置不成功如何去排查问题? [问题解答] 华为推送怎么设置角标? 1.消息体设置 我们可以参考桌面角标这一篇文档进行设置角标 ​ 2.端测 ...

  7. 修改后台传过来的json数据中对象的属性

    前言 今天在实习中遇到的一个小问题,后端传过来的一个json数据结构,但是对象中的属性名跟我需要的不一样(因为我是渲染echarts中的数据,属性名要一样) 这是后台传过来的数据: 需求是我需要把属性 ...

  8. Spring源码 18 IOC refresh方法13

    参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...

  9. SpringBoot整合Redis实现常用功能

    SpringBoot整合Redis实现常用功能 建议大小伙们,在写业务的时候,提前画好流程图,思路会清晰很多. 文末有解决缓存穿透和击穿的通用工具类. 1 登陆功能 我想,登陆功能是每个项目必备的功能 ...

  10. HDU 6222 Heron and His Triangle (pell 方程)

    题面(本人翻译) A triangle is a Heron's triangle if it satisfies that the side lengths of it are consecutiv ...