LeetCode100天Day13-移除元素与多数元素

LeetCode100天Day13-移除元素与多数元素:双指针移除与排序计数

摘要:本文详细解析了LeetCode中两道经典数组题目——“移除元素"和"多数元素”。通过双指针实现原地移除元素,以及使用排序和计数查找多数元素,帮助读者掌握数组元素操作和查找的技巧。

目录

文章目录

  • LeetCode100天Day13-移除元素与多数元素:双指针移除与排序计数
    • 目录
    • 1. 移除元素(Remove Element)
      • 1.1 题目描述
      • 1.2 解题思路
      • 1.3 代码实现
      • 1.4 代码逐行解释
        • 第一部分:初始化指针
        • 第二部分:遍历数组
      • 1.5 执行流程详解
      • 1.6 算法图解
      • 1.7 复杂度分析
      • 1.8 边界情况
    • 2. 多数元素(Majority Element)
      • 2.1 题目描述
      • 2.2 解题思路
      • 2.3 代码实现
      • 2.4 代码逐行解释
        • 第一部分:计算阈值
        • 第二部分:排序
        • 第三部分:统计计数
      • 2.5 执行流程详解
      • 2.6 算法图解
      • 2.7 复杂度分析
      • 2.8 边界情况
    • 3. 两题对比与总结
      • 3.1 算法对比
      • 3.2 双指针移除模板
      • 3.3 排序+计数模板
      • 3.4 摩尔投票法
      • 3.5 整数除法陷阱
    • 4. 总结
    • 参考资源
    • 文章标签

1. 移除元素(Remove Element)

1.1 题目描述

给你一个数组nums和一个值val,你需要原地移除所有数值等于val的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

示例 1

输入:nums = [3,2,2,3], val = 3 输出:2, nums = [2,2,_,_] 解释:函数应该返回新的长度2,并且nums中的前两个元素均为2。你不需要考虑数组中超出新长度后面的元素。

示例 2

输入:nums = [0,1,2,2,3,0,4,2], val = 2 输出:5, nums = [0,1,3,0,4,_,_,_] 解释:函数应该返回新的长度5,并且nums中的前五个元素为0, 1, 3, 0, 4。注意这五个元素可以任意顺序。你不需要考虑数组中超出新长度后面的元素。

1.2 解题思路

这道题使用双指针的方法:

  1. 使用慢指针k指向下一个非val元素应该放置的位置
  2. 使用快指针i遍历数组
  3. 当遇到不等于val的元素时,将其放到k的位置,然后k++
  4. 返回k

解题步骤

  1. 初始化k=0
  2. 遍历数组,检查每个元素
  3. 如果当前元素不等于val,将其放到nums[k],k++
  4. 返回k

1.3 代码实现

classSolution{publicintremoveElement(int[]nums,intval){intk=0;for(inti=0;i<nums.length;i++){if(nums[i]!=val){nums[k]=nums[i];k++;}}returnk;}}

1.4 代码逐行解释

第一部分:初始化指针
intk=0;

功能

  • k是慢指针(写指针),指向下一个非val元素应该放置的位置
  • 初始值为0,表示从数组开头开始写入
第二部分:遍历数组
for(inti=0;i<nums.length;i++){if(nums[i]!=val){nums[k]=nums[i];k++;}}

指针说明

指针作用说明
i快指针(读指针)遍历整个数组
k慢指针(写指针)指向写入位置

判断逻辑

if(nums[i]!=val)
条件操作
nums[i] != val保留元素,写入nums[k]
nums[i] == val跳过,不写入

写入逻辑

nums[k]=nums[i];k++;
操作说明
nums[k] = nums[i]将非val元素复制到k位置
k++移动到下一个写入位置

1.5 执行流程详解

示例1nums = [3,2,2,3], val = 3

初始状态: nums = [3, 2, 2, 3] k = 0 i=0: nums[0] = 3 3 != 3? 否,跳过 k = 0 i=1: nums[1] = 2 2 != 3? 是 nums[0] = 2 nums = [2, 2, 2, 3] k = 1 i=2: nums[2] = 2 2 != 3? 是 nums[1] = 2 nums = [2, 2, 2, 3] k = 2 i=3: nums[3] = 3 3 != 3? 否,跳过 k = 2 循环结束,返回 k = 2 最终数组前2个元素: [2, 2]

示例2nums = [0,1,2,2,3,0,4,2], val = 2

初始状态: nums = [0, 1, 2, 2, 3, 0, 4, 2] k = 0 i=0: nums[0]=0, 0 != 2? 是 nums[0] = 0, k = 1 i=1: nums[1]=1, 1 != 2? 是 nums[1] = 1, k = 2 i=2: nums[2]=2, 2 != 2? 否,跳过 i=3: nums[3]=2, 2 != 2? 否,跳过 i=4: nums[4]=3, 3 != 2? 是 nums[2] = 3, k = 3 i=5: nums[5]=0, 0 != 2? 是 nums[3] = 0, k = 4 i=6: nums[6]=4, 4 != 2? 是 nums[4] = 4, k = 5 i=7: nums[7]=2, 2 != 2? 否,跳过 循环结束,返回 k = 5 最终数组前5个元素: [0, 1, 3, 0, 4]

1.6 算法图解

初始数组: [3, 2, 2, 3], val = 3 索引: 0 1 2 3 步骤1: i=0, k=0 数组: [3, 2, 2, 3] 索引: ↑ i=0, k=0 nums[0] = 3, 等于val,跳过 步骤2: i=1, k=0 数组: [3, 2, 2, 3] 索引: ↑ ↑ k=0 i=1 nums[1] = 2, 不等于val nums[0] = 2 数组: [2, 2, 2, 3] k = 1 步骤3: i=2, k=1 数组: [2, 2, 2, 3] 索引: ↑ ↑ k=1 i=2 nums[2] = 2, 不等于val nums[1] = 2 数组: [2, 2, 2, 3] k = 2 步骤4: i=3, k=2 数组: [2, 2, 2, 3] 索引: ↑ ↑ k=2 i=3 nums[3] = 3, 等于val,跳过 最终结果: k = 2 数组前2个元素: [2, 2]

1.7 复杂度分析

分析维度复杂度说明
时间复杂度O(n)遍历数组一次
空间复杂度O(1)只使用常数空间

优化思路:当遇到val时,可以与数组末尾元素交换,减少写入次数

// 优化版本:双指针从两端classSolution{publicintremoveElement(int[]nums,intval){intleft=0;intright=nums.length-1;while(left<=right){if(nums[left]==val){nums[left]=nums[right--];}else{left++;}}returnleft;}}

1.8 边界情况

numsval说明输出
[]1空数组0
[1]1单个待删除0
[1]2单个保留1
[3,3,3]3全部删除0
[1,2,3]4无需删除3

2. 多数元素(Majority Element)

2.1 题目描述

给定一个大小为n的数组nums,返回其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例 1

输入:nums = [3,2,3] 输出:3

示例 2

输入:nums = [2,2,1,1,1,2,2] 输出:2

2.2 解题思路

这道题使用排序和计数的方法:

  1. 对数组进行排序
  2. 遍历排序后的数组,统计每个连续元素的出现次数
  3. 如果某个元素的出现次数大于n/2,返回该元素

解题步骤

  1. 计算阈值compare = n * 1.0 / 2
  2. 对数组排序
  3. 遍历数组,统计每个元素的出现次数
  4. 如果次数大于compare,返回该元素

2.3 代码实现

importjava.util.*;classSolution{publicintmajorityElement(int[]nums){doublecompare=nums.length*(1.0)/2;Arrays.sort(nums);inttemp=nums[0];intk=0;intanswer=nums[0];for(inti=0;i<nums.length;i++){if(temp==nums[i]){k++;if(k>compare){answer=nums[i];}}else{temp=nums[i];k=1;}}returnanswer;}}

2.4 代码逐行解释

第一部分:计算阈值
doublecompare=nums.length*(1.0)/2;

功能:计算多数元素的阈值

nums.length计算compare
33 * 1.0 / 21.5
77 * 1.0 / 23.5

为什么要用1.0

// 错误写法intcompare=nums.length/2;// 整数除法,7/2 = 3// 正确写法doublecompare=nums.length*1.0/2;// 7.0 / 2 = 3.5
第二部分:排序
Arrays.sort(nums);

功能:对数组进行升序排序

排序前排序后
[3, 2, 3][2, 3, 3]
[2, 2, 1, 1, 1, 2, 2][1, 1, 1, 2, 2, 2, 2]
第三部分:统计计数
inttemp=nums[0];intk=0;intanswer=nums[0];for(inti=0;i<nums.length;i++){if(temp==nums[i]){k++;if(k>compare){answer=nums[i];}}else{temp=nums[i];k=1;}}

变量说明

变量初始值作用
tempnums[0]当前统计的元素
k0当前元素的计数
answernums[0]多数元素的结果

统计逻辑

if(temp==nums[i]){k++;// 相同,计数加1if(k>compare){answer=nums[i];// 超过阈值,记录答案}}else{temp=nums[i];// 不同,切换到新元素k=1;// 重置计数}

2.5 执行流程详解

示例1nums = [3,2,3]

初始状态: nums = [3, 2, 3] 排序后: nums = [2, 3, 3] compare = 3 * 1.0 / 2 = 1.5 temp = nums[0] = 2 k = 0 answer = 2 i=0: nums[0] = 2 temp(2) == nums[0](2)? 是 k = 1 1 > 1.5? 否 i=1: nums[1] = 3 temp(2) == nums[1](3)? 否 temp = 3 k = 1 i=2: nums[2] = 3 temp(3) == nums[2](3)? 是 k = 2 2 > 1.5? 是 answer = 3 循环结束,返回 answer = 3 输出: 3

示例2nums = [2,2,1,1,1,2,2]

初始状态: nums = [2, 2, 1, 1, 1, 2, 2] 排序后: nums = [1, 1, 1, 2, 2, 2, 2] compare = 7 * 1.0 / 2 = 3.5 temp = 1 k = 0 answer = 1 i=0: nums[0]=1, temp=1 1 == 1? 是 k = 1 1 > 3.5? 否 i=1: nums[1]=1, temp=1 1 == 1? 是 k = 2 2 > 3.5? 否 i=2: nums[2]=1, temp=1 1 == 1? 是 k = 3 3 > 3.5? 否 i=3: nums[3]=2, temp=1 1 == 2? 否 temp = 2 k = 1 i=4: nums[4]=2, temp=2 2 == 2? 是 k = 2 2 > 3.5? 否 i=5: nums[5]=2, temp=2 2 == 2? 是 k = 3 3 > 3.5? 否 i=6: nums[6]=2, temp=2 2 == 2? 是 k = 4 4 > 3.5? 是 answer = 2 循环结束,返回 answer = 2 输出: 2

2.6 算法图解

初始数组: [2, 2, 1, 1, 1, 2, 2] 排序后: [1, 1, 1, 2, 2, 2, 2] 阈值: 3.5 步骤1: i=0, temp=1, k=0 数组: [1, 1, 1, 2, 2, 2, 2] 索引: ↑ i=0 nums[0]=1 == temp=1 k = 1 1 > 3.5? 否 步骤2: i=1, temp=1, k=1 数组: [1, 1, 1, 2, 2, 2, 2] 索引: ↑ i=1 nums[1]=1 == temp=1 k = 2 2 > 3.5? 否 步骤3: i=2, temp=1, k=2 数组: [1, 1, 1, 2, 2, 2, 2] 索引: ↑ i=2 nums[2]=1 == temp=1 k = 3 3 > 3.5? 否 步骤4: i=3, temp=1, k=3 数组: [1, 1, 1, 2, 2, 2, 2] 索引: ↑ i=3 nums[3]=2 != temp=1 temp = 2 k = 1 步骤5-7: 继续统计2 k = 2, 3, 4 4 > 3.5? 是 answer = 2 最终结果: 2

2.7 复杂度分析

分析维度复杂度说明
时间复杂度O(n log n)排序的复杂度
空间复杂度O(1)取决于排序实现

优化思路:可以使用摩尔投票法优化到O(n)

// 优化版本:摩尔投票法classSolution{publicintmajorityElement(int[]nums){intcount=0;Integercandidate=null;for(intnum:nums){if(count==0){candidate=num;}count+=(num==candidate)?1:-1;}returncandidate;}}

2.8 边界情况

nums说明输出
[1]单元素1
[1,1]两元素1
[1,2,1]交替出现1
[2,2,1,1,1,2,2]复杂情况2

3. 两题对比与总结

3.1 算法对比

对比项移除元素多数元素
核心算法双指针排序+计数
数据结构数组数组
时间复杂度O(n)O(n log n)
空间复杂度O(1)O(1)
应用场景删除特定元素查找多数元素

3.2 双指针移除模板

// 双指针移除元素模板intk=0;// 写指针for(inti=0;i<nums.length;i++){// 读指针if(nums[i]!=target){// 保留条件nums[k++]=nums[i];}}returnk;

3.3 排序+计数模板

// 排序+计数模板Arrays.sort(array);Typecurrent=array[0];intcount=0;for(inti=0;i<array.length;i++){if(array[i]==current){count++;if(count>threshold){returnarray[i];}}else{current=array[i];count=1;}}

3.4 摩尔投票法

核心思想

  • 不同元素相互抵消
  • 剩下的元素就是多数元素
// 摩尔投票法模板intcount=0;Typecandidate=null;for(Typenum:array){if(count==0){candidate=num;}count+=(num==candidate)?1:-1;}returncandidate;

投票过程

数组: [2, 2, 1, 1, 1, 2, 2] num=2: count=0, candidate=2, count=1 num=2: count=1, candidate=2, count=2 num=1: count=2, candidate=2, count=1 (抵消) num=1: count=1, candidate=2, count=0 (抵消) num=1: count=0, candidate=1, count=1 num=2: count=1, candidate=1, count=0 (抵消) num=2: count=0, candidate=2, count=1 最终: candidate=2

3.5 整数除法陷阱

// 整数除法inta=7/2;// a = 3 (向下取整)// 浮点数除法doubleb=7*1.0/2;// b = 3.5// 比较时if(count>n/2){// 错误:7/2=3,需要>3// count=4时才满足,但实际需要>3.5}if(count>n*1.0/2){// 正确// count=4时满足}

4. 总结

今天我们学习了两道数组操作题目:

  1. 移除元素:掌握双指针移除特定元素,理解原地修改的技巧
  2. 多数元素:掌握排序+计数查找多数元素,理解统计计数的逻辑

核心收获

  • 双指针可以实现原地移除元素,空间复杂度O(1)
  • 排序后相同元素会连续,便于统计
  • 计数时注意整数除法的陷阱
  • 摩尔投票法是查找多数元素的高效方法

练习建议

  1. 尝试用双指针从两端优化移除元素
  2. 学习摩尔投票法并实现
  3. 思考如何找到出现次数前k多的元素

参考资源

  • LeetCode 中国站 - 移除元素
  • LeetCode 中国站 - 多数元素
  • 双指针算法详解
  • 摩尔投票法

文章标签

#LeetCode #算法 #Java #数组 #双指针

喜欢这篇文章吗?别忘了点赞、收藏和分享!你的支持是我创作的最大动力!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1172796.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2026年卷闸门厂家专业推荐榜:自动/车库/电动/不锈钢/快速卷闸门及工业门解决方案厂家精选 - 品牌推荐官

中国自动化工业门市场正经历着深刻变革,据行业报告显示,2025年中国市场规模已达到438.36亿元人民币,全球市场则接近2000亿元人民币,且预计将以年复合增长率超过9% 的速度持续增长。在这一庞大的市场中,卷闸门产品…

重磅福利,TRAE 国际版全部用户限免一个月!

前言好消息&#xff0c;TRAE 官方宣布为庆祝上线一周年 TRAE 国际版全部用户限免一个月&#xff01;即从 2026 年 1 月 14 日 10:00 起&#xff0c;TRAE 国际版全部用户赠送 Fast Request 权益&#xff08;不少于 1 个月 Pro 会员的用量&#xff09;&#xff01;Free 用户&…

智纺云ERP开发实战

基于Spring Boot React的纺织品ERP管理系统全栈开发实战 本文详细介绍了一个企业级纺织品ERP管理系统的完整开发过程,涵盖需求分析、技术选型、架构设计、核心功能实现等方面。该系统采用前后端分离架构,后端使用Spring Boot MyBatis MySQL,前端使用React Tailwind CSS,实现…

推荐几个不错的 Linux 服务器管理工具

前言选择一款好的 Linux 服务器管理工具能够极大地提高运维效率&#xff0c;保障业务连续性。今天大姚给大家分享3款不错的 Linux 服务器管理工具&#xff0c;希望可以帮助到有需要的同学。1Panel1Panel是新一代的 Linux 服务器运维管理面板&#xff0c;旨在通过现代化的 Web 界…

【算法题】堆

堆&#xff08;优先队列&#xff09;是一种基于完全二叉树的动态数据结构&#xff0c;核心特性是快速获取最值&#xff08;大根堆获取最大值&#xff0c;小根堆获取最小值&#xff09;&#xff0c;插入和删除操作的时间复杂度均为 O(log⁡n)O(\log n)O(logn)。它广泛应用于“动…

PasteEx:一款.NET开源的Windows快捷粘贴神器

前言PasteEx是一款.NET开源的用于增强 Windows 粘贴功能的小工具&#xff0c;它解决了将剪贴板内容保存为文件的繁琐步骤。无需打开记事本等应用&#xff0c;它可直接将文字、图片等内容粘贴到桌面上&#xff0c;极大提升了效率。功能特点自定义文本扩展规则&#xff1a;用户可…

2026年膏滋贴牌/拿货/定制/实力厂家推荐:湖北李时珍大健康源头工厂 - 品牌推荐官

在健康消费升级的浪潮下,膏滋类产品凭借其天然、便捷的特性,成为大健康市场的热门品类。据行业数据显示,2025年国内膏滋市场规模已突破120亿元,年复合增长率达18%,其中定制化、品牌化需求占比超65%。面对这一趋势…

《云计算到底是什么?IaaS/PaaS/SaaS 怎么分?一篇读懂不踩坑》

一、云计算&#xff1a;不止是技术&#xff0c;更是 IT 消费模式的革命 提到云计算&#xff0c;很多人会联想到 “把数据存到云上”&#xff0c;但这只是冰山一角。云计算的本质&#xff0c;是新技术与 IT 业务模式的双重创新—— 它通过技术将 IT 资源池化、服务化&#xff0…

C/C++访问MySQL数据库

C/C访问MySQL数据库 VS2019配置 第一步&#xff1a;打开mysql的安装目录&#xff0c;默认安装目录如下&#xff1a;C:\Program Files\MySQL\MySQL Server 8.0&#xff0c;确认 lib 目录和include 目录是否存在。 第二步&#xff1a;打开VS2019&#xff0c;新建一个空工程,控制台…

打工人学生党必看!Trilium Notes + cpolar,知识管理不被地点绑死

Trilium Notes 是一款主打结构化知识管理的开源笔记软件&#xff0c;支持树状层级组织笔记&#xff0c;可编辑富文本、Markdown、LaTeX 公式、Mermaid 流程图等内容&#xff0c;还具备全文检索、笔记加密、版本控制等功能&#xff0c;能适配不同人群的笔记整理需求&#xff0c;…

精选 4 款基于 C# 开源、实用的工具类库,开发效率提升利器!

前言 在我们日常工作开发中工具类库是软件开发中不可或缺的一部分&#xff0c;它们通过提供通用功能、实现代码复用、封装复杂逻辑、提升代码质量与可维护性&#xff0c;帮助开发者更高效、更稳定地构建软件应用程序。 今天大姚给大家分享 4 款基于 C# 开源、免费、实用的工具…

强烈安利专科生必看!10个AI论文网站深度测评

强烈安利专科生必看&#xff01;10个AI论文网站深度测评 2026年专科生必备的AI论文工具测评 随着人工智能技术的不断进步&#xff0c;越来越多的专科生开始借助AI工具提升论文写作效率。然而&#xff0c;面对市场上琳琅满目的AI论文网站&#xff0c;如何选择真正适合自己需求的…

实测!旧手机秒变 Web 服务器,KSWEB+cpolar 摆脱局域网束缚

KSWEB 是一款专为安卓设备设计的 Web 服务器软件&#xff0c;它内置了 PHP、MySQL、Apache 等核心组件&#xff0c;无需繁琐的环境配置&#xff0c;就能让安卓手机变身 Web 服务器&#xff0c;支持部署 Typecho 这类轻量级博客系统&#xff0c;还附带 phpAdmin 工具方便管理数据…

2026年浊度仪优质厂家推荐排名,选择不用愁! - 工业品牌热点

本榜单依托全维度市场调研与真实行业口碑,深度筛选出五家标杆企业,为工业自动化领域企业选型浊度仪提供客观依据,助力精准匹配适配的服务伙伴。 TOP1 推荐:杭州联测自动化技术有限公司 推荐指数:★★★★★ | 口碑…

GESP认证C++编程真题解析 | P11960 [GESP202503 五级] 平均分配

​欢迎大家订阅我的专栏&#xff1a;算法题解&#xff1a;C与Python实现&#xff01; 本专栏旨在帮助大家从基础到进阶 &#xff0c;逐步提升编程能力&#xff0c;助力信息学竞赛备战&#xff01; 专栏特色 1.经典算法练习&#xff1a;根据信息学竞赛大纲&#xff0c;精心挑选…

GESP认证C++编程真题解析 | P11961 [GESP202503 五级] 原根判断

​欢迎大家订阅我的专栏&#xff1a;算法题解&#xff1a;C与Python实现&#xff01; 本专栏旨在帮助大家从基础到进阶 &#xff0c;逐步提升编程能力&#xff0c;助力信息学竞赛备战&#xff01; 专栏特色 1.经典算法练习&#xff1a;根据信息学竞赛大纲&#xff0c;精心挑选…

springboot医疗器械预定小程序设计开发实现

开发背景医疗器械预定小程序基于SpringBoot的开发需求主要源于医疗行业数字化转型的迫切性。传统医疗器械采购流程存在效率低、信息不透明、管理困难等问题&#xff0c;而移动互联网技术的普及为优化这一流程提供了技术基础。行业痛点&#xff1a;医疗机构常面临器械库存不清、…

ssm自习室预约小程序的设计与实现

背景分析近年来&#xff0c;高校及公共学习场所的自习资源紧张问题日益突出&#xff0c;学生面临“占座难”“管理混乱”等痛点。传统人工登记方式效率低下&#xff0c;纸质签到易丢失数据&#xff0c;难以满足高峰时段的预约需求。数字化管理成为提升资源利用率的必然趋势。社…

上海装修设计选哪家?2026年优质公司精选,法式大平层设计/软装设计/奶油风房屋装修,上海装修设计团队推荐榜 - 品牌推荐师

随着上海城市化进程加速与居住品质升级,装修设计行业迎来结构性变革。消费者对设计落地性、环保标准、工程透明度及售后服务的要求持续提升,推动市场向专业化、精细化方向发展。据上海市室内装饰行业协会数据显示,2…

基于天牛须(BAS)与NSGA-Ⅱ混合算法的交直流混合微电网多场景多目标优化调度(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&a…