每日一题——力扣26. 删除有序数组中的重复项(举一反三)

34f0aab6124a400bb321dd38682233c3.jpeg

一个认为一切根源都是“自己不够强”的INTJ

b450501d80dc4e5e820b4403e45bc84a.png个人主页:用哲学编程-CSDN博客
b450501d80dc4e5e820b4403e45bc84a.png​专栏:每日一题——举一反三

目录

我的写法:

代码点评:

时间复杂度分析:

空间复杂度分析:

总结:

我要更好!

这种方法体现了以下哲学和编程思想:

举一反三!


 

题目链接:https://leetcode.cn/problems/remove-duplicates-from-sorted-array/description/
d7ef6b4178764c31b0c6a977ee54f541.png

我的写法:

// 定义一个函数,用于移除数组中的重复元素,并返回新数组的长度
int removeDuplicates(int* nums, int numsSize) {// 如果数组只有一个元素,那么它没有重复,直接返回1if(numsSize==1){return 1;}// 初始化变量:i 用于记录不重复元素的位置,j 用于遍历数组,xor 用于异或操作,counts_re 用于记录重复元素的数量int i,j,xor,counts_re;// 初始化循环变量,xor 初始化为数组的第一个元素,counts_re 初始化为0for(i=0,j=1,xor=nums[0],counts_re=0;j<numsSize;j++){// 对当前元素和 xor 进行异或操作,xor 初始为前一个元素的值xor^=nums[j];// 如果异或结果为0,说明当前元素与前一个元素相同,计数器 counts_re 增加if(xor==0){counts_re++;}else{// 如果异或结果不为0,说明当前元素与前一个元素不同,将当前元素移动到 i 指向的位置,并增加 ii++;nums[i]=nums[j];}// 更新 xor 为当前元素的值,以便下一次循环使用xor=nums[j];}// 返回原数组长度减去重复元素的数量,即新数组的长度return numsSize-counts_re;
}

这段代码的目的是移除数组中的重复元素,并返回新数组的长度。下面是对这段代码的专业点评,包括时间复杂度和空间复杂度的分析:

代码点评:

  1. 逻辑清晰:代码的逻辑是清晰的,通过异或操作来判断相邻元素是否相同,这是一种有效的比较方法。
  2. 边界条件处理:代码考虑了数组只有一个元素的情况,并正确处理了这种边界条件。
  3. 双指针技术:使用 i 和 j 两个指针来遍历数组,i 用于记录不重复元素的位置,j 用于遍历整个数组,这是一种常见的双指针技术。
  4. 重复计数:通过 counts_re 变量来记录重复元素的数量,这是一种有效的计数方法。
  5. 原地修改:代码在原数组上进行修改,没有使用额外的数组空间,这有助于节省内存。

时间复杂度分析:

  • 时间复杂度:这段代码的时间复杂度是 O(n),其中 n 是数组的长度。这是因为代码使用了一个循环来遍历整个数组,每个元素只被访问一次。

空间复杂度分析:

  • 空间复杂度:这段代码的空间复杂度是 O(1),即常数级别的额外空间使用。这是因为代码只使用了几个额外的变量(i、j、xor、counts_re),并没有使用与输入规模成比例的额外空间。

总结:

这段代码是一个有效的方法,用于移除数组中的重复元素,并返回新数组的长度。它的时间复杂度是 O(n),空间复杂度是 O(1),表明它是一个高效的解决方案。不过其中的变量xor是多余的。
 

我要更好!

要去除 xor 变量并保持代码功能不变,可以直接比较当前元素 nums[j] 和它前一个元素 nums[i]。当两者不相等时,应当将 nums[j] 移动到 nums[i+1] 的位置,并增加 i 的值,这样可以保持 nums[i] 始终指向最新的不重复元素的位置。

修改后的代码:

int removeDuplicates(int* nums, int numsSize) {// 如果数组大小小于或等于1,它要么为空,要么已经没有重复元素if (numsSize <= 1) return numsSize;// i 用于记录最新的不重复元素的位置int i = 0; // 从第一个元素开始,i 指向最后一个不重复元素的位置for (int j = 1; j < numsSize; j++) {// 当前元素与前一个不重复的元素比较if (nums[j] != nums[i]) {// 当发现不重复的元素时,移动到i的下一个位置i++;nums[i] = nums[j];}}// 新数组长度为最后一个不重复元素的索引 + 1return i + 1;
}

这个版本,去掉了 xor 变量,这样做的好处是简化了逻辑,同时避免了对异或操作的不必要依赖。原本的 xor 逻辑更多是为了理解异或操作如何工作,而在实际应用中直接比较相邻元素通常更直接和易于理解。这个改进的版本仍旧遵循 O(n) 的时间复杂度和 O(1) 的空间复杂度,适用于大多数需要去重复元素的场景。

这种方法体现了以下哲学和编程思想:

  1. 简洁性(Simplicity):通过去除不必要的变量(如 xor),代码变得更加简洁和易于理解。这种简洁性是编程中的一个重要原则,因为它有助于减少错误和提高代码的可维护性。
  2. 增量式开发(Incremental Development):代码逐步构建,每次只处理一个元素,确保每个步骤都是正确的。这种增量式的方法有助于在开发过程中及时发现和纠正问题。
  3. 迭代(Iteration):使用循环(for 循环)来遍历数组中的每个元素,这是编程中处理重复任务的常用方法。迭代是编程中的一个基本概念,它允许程序重复执行相同的代码块,直到满足某个条件。
  4. 抽象(Abstraction):通过函数 removeDuplicates 将去重逻辑封装起来,使得调用者不需要关心具体的实现细节,只需要知道函数的功能和输入输出。这种抽象有助于提高代码的可读性和可重用性。
  5. 单一职责原则(Single Responsibility Principle):函数 removeDuplicates 只负责一个任务,即移除数组中的重复元素。这种单一职责原则有助于保持代码的清晰和模块化。
  6. 空间和时间的权衡(Space-Time Tradeoff):虽然原始代码使用了一个额外的变量 xor,但修改后的代码避免了这种空间上的开销,同时保持了时间复杂度为 O(n)。这种权衡是算法设计中的一个常见考虑因素。
  7. 函数式编程思想(Functional Programming):虽然这段代码是命令式的,但它体现了函数式编程中的一些思想,如避免副作用(函数内部的操作不改变输入数组以外的状态)和使用纯函数(给定相同的输入,总是产生相同的输出)。
  8. 实用主义(Pragmatism):代码的目的是解决问题,而不是追求理论上的完美。在这个例子中,通过实际的比较操作来移除重复元素,而不是使用理论上可能更优雅但实际应用中可能更复杂的解决方案。


举一反三!
 

根据移除数组中重复元素的方法,这里提供一些编程技巧,帮助您在其他场景下举一反三:

  1. 理解问题的本质:在开始编码之前,花时间搞清楚问题的实质。去除数组重复元素的问题的本质是识别和保留唯一的元素,这个理解帮助简化解决方案。
  2. 预设条件优化:利用已知的条件(如排序数组)来简化算法。在排序数组中去除重复元素更容易,因为重复项总是连续出现的。
  3. 修改原地:尽可能地原地修改数组,这样可以节省额外的内存空间。在处理大数据量时,原地算法非常有用。
  4. 双指针技巧:使用两个指针在一个循环中分别追踪不同的信息。在本例中,一个指针追踪不重复序列的末尾,另一个追踪当前读到的元素。
  5. 不怕简单:有时候最简单的解决方案就是最佳方案。不要过度设计,避免引入不必要的复杂性。
  6. 避免不必要的操作:在可能的情况下,避免不必要的计算和比较,这可以通过直接比较相邻元素来实现,而不是采用更复杂的算法。
  7. 重构代码:重构代码以提高可读性和性能。即使你的第一个解决方案是有效的,通过重构,你可能会发现一个更优雅或更快的方法。
  8. 递增索引管理:在处理数组和列表时,理解如何使用递增索引来有效地管理元素位置和遍历。
  9. 测试边界条件:当编写函数时,要考虑并测试边界条件,例如空数组、只有一个元素的数组或所有元素都相同的数组。
  10. 编写可重用代码:将通用的解决方案抽象成函数或模块,以便在不同的问题中重用它们,提高代码的可复用性。

本节内容到此结束!!感谢阅读!

 

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

ue引擎游戏开发笔记(41)——行为树的建立(2)--丰富ai行为:巡逻后返回原处

1.需求分析&#xff1a; 就敌人ai而言&#xff0c;追踪到敌人有可能丢失目标&#xff0c;丢失目标后应该能返回原来位置&#xff0c;实现这一功能。 2.操作实现&#xff1a; 1.思路&#xff1a;利用clear value函数&#xff0c;禁用掉当前的追踪功能&#xff0c;执行之后的返…

Java | Leetcode Java题解之第91题解码方法

题目&#xff1a; 题解&#xff1a; class Solution {public int numDecodings(String s) {int n s.length();// a f[i-2], b f[i-1], cf[i]int a 0, b 1, c 0;for (int i 1; i < n; i) {c 0;if (s.charAt(i - 1) ! 0) {c b;}if (i > 1 && s.charAt(i …

C++ 计时器

文章目录 一、简介二、实现代码2.1 windows平台2.2 C标准库 三、实现效果 一、简介 有时候总是会用到一些计时的操作&#xff0c;这里也整理了一些代码&#xff0c;包括C标准库以及window自带的时间计算函数。 二、实现代码 2.1 windows平台 StopWatch.h #ifndef STOP_WATCH_H…

C++ static_cast学习

static_cast可实现&#xff0c; 1 基本类型之间的转换 2 void指针转换为任意基本类型的指针 3 用于有继承关系的子类与父类之间的指针或引用的转换 用于基本类型转化时&#xff0c;会损失精度类似于C语言的强制转化&#xff1b; 下面先看一下void指针的转换&#xff1b; …

CSS学习笔记之中级教程(二)

-.CSS学习笔记之中级教程&#xff08;一&#xff09; 6、CSS 布局 - display: inline-block 与 display: inline 相比&#xff0c;主要区别在于 display: inline-block 允许在元素上设置宽度和高度。 同样&#xff0c;如果设置了 display: inline-block&#xff0c;将保留上下…

【数据库】知识总结(期末复习)

题型&#xff1a; 一、选择题(共10题&#xff0c;每题2分&#xff0c;共20分) 二、填空题(共10空&#xff0c;每空1分&#xff0c;共10分) 三、关系代数计算题&#xff08;共5题&#xff0c;每题2分&#xff0c;共10分&#xff09; 四、SQL计算题(共10题&#xff0c;每题3分…

C++ | Leetcode C++题解之第92题反转链表II

题目&#xff1a; 题解&#xff1a; class Solution { public:ListNode *reverseBetween(ListNode *head, int left, int right) {// 设置 dummyNode 是这一类问题的一般做法ListNode *dummyNode new ListNode(-1);dummyNode->next head;ListNode *pre dummyNode;for (i…

东莞酷得电子方案 遥控水弹坦克车

首先遥控小车是一种能够通过无线遥控器进行远程操控的小型机器人。遥控小车应用了哪些软硬件技术呢&#xff1f;本文将从以下几个方面进行详细介绍。 遥控小车应用了多种软硬件技术&#xff0c;涉及底盘结构、动力系统、传感器、控制器等多个方面。 底盘结构&#xff1a;遥控…

PostgreSQL扩展之PGroonga:多语言全文搜索

简介 PGroonga 是一个 PostgreSQL 扩展&#xff0c;它增加了基于 Groonga 的全文搜索索引方法。虽然原生的 PostgreSQL 支持全文索引&#xff0c;但它仅限于基于字母和数字的语言。PGroonga 提供了更广泛的字符支持&#xff0c;使其成为 PostgreSQL 支持的语言的超集&#xff…

【考研数学】张宇《1000题》强化阶段正确率多少算合格?

张宇1000题真的很练人心态.... 基础不好&#xff0c;建议别碰1000题 基础好&#xff0c;1000题建议在两个月以内刷完 如果自己本身在基础阶段学的比较水&#xff0c;自己的薄弱点刷了一小部分题没有针对性完全解决&#xff0c;转身去刷1000题就会发现&#xff0c;会的题目刷…

一线互联网大数据面试题核心知识库(100万字)

本面试宝典涵盖大数据面试高频的所有技术栈&#xff0c;包括Liunx&Shell基础&#xff0c;Hadoop&#xff0c;Zookpeer&#xff0c;Flume&#xff0c;Kafka&#xff0c;Hive&#xff0c;Datax&#xff0c;Maxwell&#xff0c;DolphinScheduler&#xff0c;Spark Core&SQ…

王炸!OpenAI全新模型GPT-4o推出!免费使用,实时语音视频交互来了!

北京时间5月14日凌晨&#xff0c;OpenAI 春季新品发布会举行&#xff0c;新一代旗舰生成模型 GPT-4o来了。GPT-4o 的推出代表着技术进步的一大步&#xff0c;集成了文本、语音和图像三种模态&#xff0c;使人机交互更加自然和高效。 这样的话&#xff0c;目前可以使用的版本包括…

[Linux][网络][高级IO][三][IO多路转接][epoll]详细讲解

目录 1.IO多路转接之epoll1.epoll初识2.epoll_create()3.epoll_ctl()4.epoll_wait()5.epoll工作原理6.epoll使用过程三部曲7.epoll的优点(和select缺点对应)8.思考 && 问题 2.epoll工作方式0.感性理解 && 铺垫1.水平触发(Level Triggered)工作模式2.边缘触发(E…

webpack优化构建速度示例-externals:

externals 配置项主要用于防止将某些 import 的包&#xff08;package&#xff09;打包到 bundle 中&#xff0c;而是在运行时&#xff08;runtime&#xff09;再从外部获取这些扩展依赖&#xff08;external dependencies&#xff09;。这样做的主要目的是为了解决打包文件过大…

cypress的安装使用

cypress npm install -g cnpm --registryhttps://registry.npm.taobao.org cypress的启动打开 npx cypress open js函数的回调 function print(string,callback){console.log(string)callback() } print("a",function(){print("b",function(){console.l…

spark知识点

目录 第二章Scala基础 一.Scala常用数据类型 二.定义与使用数组 三.定义与使用函数 四.定义与使用列表 五.定义与使用集合 六.定义与使用映射 七.定义与使用元组 第三章Spark编程基础 一.从内存中读取创建RDD 二.从外部存储系统中读取数据创建RDD 三.RDD方法归纳 1.…

Qt+C++串口调试工具

程序示例精选 QtC串口调试工具 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《QtC串口调试工具》编写代码&#xff0c;代码整洁&#xff0c;规则&#xff0c;易读。 学习与应用推荐首选。 …

异步编程CompletableFuture总结

文章目录 1. 简介&#xff1a;2. 比较1、传统方式2、使用CompletableFuture&#xff1a;异步执行返回值 3、组合处理&#xff1a;anyOfallof : 4. 异步回调&#xff1a;thenAcceptthenApplywhenComplete等同于 thenAccepthandel()等同于thenApply 5. 常用方法&#xff1a;1、su…

Vue的学习 —— <路由与网络请求>

目录 前言 正文 一、初识路由 二、初识Vue Router 1、安装Vue Router 2、Vue Router基本使用 三、路由重定向 四、嵌套路由 前言 在之前的学习中了解到单页Web应用通常只有一个HTML页面&#xff0c;所有的组件展示和切换都在这个页面上完成。虽然我们可以通过动态组件…

基于CentOS-7搭建hadoop3.3.6大数据集群(保姆级教程)

目录 安装虚拟机 为hadoop用户添加权限 关闭防火墙 修改主机名以及ip地址映射 配置ip 连接xshell &#xff0c;以hadoop用户登录 创建目录并将该文件夹权限赋予hadoop用户 安装配置jdk 关闭虚拟机&#xff0c;克隆其他两个节点 修改主机名和ip地址 配置免密登录 安装…