剑指 Offer(第 2 版)刷题 | 03. 数组中重复的数字

简介: 本文是作者针对《剑指 Offer(第 2 版)》中 "数组中重复的数字" 问题的刷题记录,分享了使用排序算法和相邻比较大小两种方法来找出数组中的重复数字,并提供了C++的实现代码。

题目 03.找出数组中重复的数字

在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

示例 1:

输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3

限制:

2 <= n <= 100000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

我的解法:

(1)先排序
(2)相邻比较大小

(1)排序算法

尝试了c++常用的排序算法,在未测试递归的情况下,测试发现插入排序算法速度最优,在一定编译时间内通过的还有希尔排序。下面理解一下,插入排序和希尔排序。

插入排序

对于第K个元素,将该元素的值存储在零时变量中,比较第前一个元素与该元素的大小,如果大于该元素就将前一个元素往后移动一步;
比较前面第二个元素与该元素的大小,如果大于该元素就将前第二个元素往后移动一步;
重复上述过程直到找到小于等于原来第K个元素(保存在零时变量中)的位置,并将第K个元素插入到这个元素的后面。或者找不到小于等于第K个元素的位置,就将原来第K个元素插入到数组的首地址。
————————————————
版权声明:本文为CSDN博主「liqinzhe223」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/liqinzhe11/article/details/78743743

代码如下:

        //插入排序  44ms
        int n = nums.size();
        for (int i = 1; i < n; i++)
        {
   
            int insert_num = nums[i], j;
            for (j = i - 1; j >= 0; j--)
            {
   
                if (nums[j] > insert_num)
                    nums[j + 1] = nums[j];
                else
                    break;
            }
            nums[j + 1] = insert_num; //重要,后移的关键一步,类似交换
        }

将第K个元素插入到这个元素的后面,需要理解如下的中间过程。

3个数[1,3,2], 经历如上代码,依次中间过程如下:

i = 1, j = 0, insert_num = nums[1] = 3;

nums[0] < nums[1] ;

无break; j = 0 ;

nums[1] = insert_num = 3; 3个数变为[1,3,2]

i = 2, j = 1, insert_num = nums[2] = 2;

nums[1] > nums[2] ;

nums[2] = nums[1];

3个数变为[1,3,3];

i = 2 , j = 0,insert_num = nums[2] = 2;

nums[0] < nums[1] ;

break; j = 0 ;

nums[1] = insert_num = 2;

3个数变为[1,2,3]

希尔排序

希尔排序是在插入排序的基础上进行发展的,通过一个希尔增量先排序一定间隔的数据。

简单的,一个希尔增量如下:

int increment = n / 2; increment > 0; increment /= 2

简单的,将插入排序中增1的地方改为增K就行。

如下三句代码:

j = i - increment; j >= 0; j -= increment;

nums[j + increment] = nums[j];

nums[j + increment] = insert_num;

        // 希尔排序 88ms
        int n = nums.size();
        for (int increment = n / 2; increment > 0; increment /= 2)
        {
   
            for (int i = increment; i < n; i++)
            {
   
                int insert_num = nums[i], j;
                for (j = i - increment; j >= 0; j -= increment)
                {
   
                    if (nums[j] > insert_num)
                        nums[j + increment] = nums[j];
                    else
                        break;
                }
                nums[j + increment] = insert_num;
            }
        }

所有非递归的排序算法代码如下:

class Solution {
   
public:
    int findRepeatNumber(vector<int>& nums) {
   
        //先排序
        //相邻比较大小
        //相等的数取出来,完成
        //输出结果
        int repeatNum = -1;

        // 版权声明:本文为CSDN博主「liqinzhe223」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
        // 原文链接:https://blog.csdn.net/liqinzhe11/article/details/78743743
        //冒泡排序1  编译成功,超出时间限制
        // int n = nums.size();
        // for (int i = 0; i < n; i++)
        // {
   
        //     for (int j = 0; j < n - 1 - i; j++)
        //     {
   
        //         if (nums[j] > nums[j+1])
        //             swap(nums[j], nums[j+1]);
        //     }
        // }

        //冒泡排序2  编译成功,超出时间限制
        // int n = nums.size();
        // bool flag;
        // for (int i = 0; i < n; i++)
        // {
   
        //     flag = false;
        //     for (int j = 0; j < n - 1 - i; j++)
        //     {
   
        //         if (nums[j] > nums[j+1])
        //         {
   
        //             swap(nums[j], nums[j+1]);
        //             flag = true;
        //         }
        //     }
        //     if (!flag)
        //         break;
        // }

        //冒泡排序3  编译成功,超出时间限制
        // int n = nums.size();
        // int flag = n;
        // int stop_pos;
        // for (int i = 0; i < n; i++)
        // {
   
        //     stop_pos = flag - 1;
        //     flag = 0;
        //     for (int j = 0; j < stop_pos; j++)
        //     {
   
        //         if (nums[j] > nums[j+1])
        //         {
   
        //             swap(nums[j], nums[j+1]);
        //             flag = j + 1;
        //         }
        //     }
        // }

        //插入排序  44ms
        int n = nums.size();
        for (int i = 1; i < n; i++)
        {
   
            int insert_num = nums[i], j;
            for (j = i - 1; j >= 0; j--)
            {
   
                if (nums[j] > insert_num)
                    nums[j + 1] = nums[j];
                else
                    break;
            }
            nums[j + 1] = insert_num;
        }

        //选择排序  编译成功,超出时间限制
        // int n = nums.size();
        // for (int i = 0; i < n - 1; i ++)
        // {
   
        //     int swap_pos = i;
        //     for (int j = i + 1; j < n; j++)
        //     {
   
        //         if (nums[swap_pos] > nums[j])
        //         {
   
        //             swap_pos = j;
        //         }
        //     }

        //     if (swap_pos != i)
        //     {
   
        //         swap(nums[swap_pos], nums[i]);
        //     }
        // }

        // // 希尔排序 88ms
        // int n = nums.size();
        // for (int increment = n / 2; increment > 0; increment /= 2)
        // {
   
        //     for (int i = increment; i < n; i++)
        //     {
   
        //         int insert_num = nums[i], j;
        //         for (j = i - increment; j >= 0; j -= increment)
        //         {
   
        //             if (nums[j] > insert_num)
        //                 nums[j + increment] = nums[j];
        //             else
        //                 break;
        //         }
        //         nums[j + increment] = insert_num;
        //     }
        // }

        // 堆排序,leetcode编译器不支持函数定义  
        //改造后  编译出错 Line 1033: Char 34: runtime error: addition of unsigned offset to 0x603000000040 overflowed to 0x603000000038 (stl_vector.h)
        // int n = nums.size();
        // int size = n;
        // while (n)
        // {
   
        //     //make_heap(a, n); //每次把新的最大元素移到堆顶,也就是nums[0]
        //     for (int i = size - 1; i > 0; i--)
        //     {
   
        //         if (i % 2 && nums[i] > nums[(i - 1) / 2])//奇数
        //             swap(nums[i], nums[(i - 1) / 2]);
        //         else if (i % 2 == 0 && nums[i] > nums[(i - 2) / 2])//偶数
        //             swap(nums[i], nums[(i - 2) / 2]);
        //     }
        //     n--;
        //     size = n;
        //     swap(nums[0], nums[n]); //然后把当前最大移动到后面来作为排好序的元素
        // }

        // 归并排序  用到递归,leetcode编译器不支持函数定义,未尝试
        // 快速排序  用到递归,leetcode编译器不支持函数定义,未尝试

        //相邻比较
        //nums[i+1],预处理超出索引问题
        if(nums[n-2]==nums[n-1])
        {
   
            repeatNum = nums[n-1];
            return nums[n-1];
        }
        //i < n-1,,预处理超出索引问题
        for(int i = 0; i < n-1 ; i++)
        {
   
            if( (nums[i] == nums[i+1]))
            {
   
                repeatNum = nums[i];//相等的数取出来
                return nums[i];
            }
        }
        return repeatNum;
    }
};

(2)相邻比较大小

主要是处理超出索引问题。

        //相邻比较
        //nums[i+1],预处理超出索引问题
        if(nums[n-2]==nums[n-1])
        {
   
            repeatNum = nums[n-1];
            return nums[n-1];
        }
        //i < n-1,,预处理超出索引问题
        for(int i = 0; i < n-1 ; i++)
        {
   
            if( (nums[i] == nums[i+1]))
            {
   
                repeatNum = nums[i];//相等的数取出来
                return nums[i];
            }
        }

参考链接:C++排序算法代码汇总

相关文章
|
11天前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
8天前
|
机器学习/深度学习 算法 大数据
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
2024“华为杯”数学建模竞赛,对ABCDEF每个题进行详细的分析,涵盖风电场功率优化、WLAN网络吞吐量、磁性元件损耗建模、地理环境问题、高速公路应急车道启用和X射线脉冲星建模等多领域问题,解析了问题类型、专业和技能的需要。
2520 17
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
|
7天前
|
机器学习/深度学习 算法 数据可视化
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
2024年中国研究生数学建模竞赛C题聚焦磁性元件磁芯损耗建模。题目背景介绍了电能变换技术的发展与应用,强调磁性元件在功率变换器中的重要性。磁芯损耗受多种因素影响,现有模型难以精确预测。题目要求通过数据分析建立高精度磁芯损耗模型。具体任务包括励磁波形分类、修正斯坦麦茨方程、分析影响因素、构建预测模型及优化设计条件。涉及数据预处理、特征提取、机器学习及优化算法等技术。适合电气、材料、计算机等多个专业学生参与。
1522 15
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
|
3天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
9天前
|
编解码 JSON 自然语言处理
通义千问重磅开源Qwen2.5,性能超越Llama
击败Meta,阿里Qwen2.5再登全球开源大模型王座
574 14
|
1月前
|
运维 Cloud Native Devops
一线实战:运维人少,我们从 0 到 1 实践 DevOps 和云原生
上海经证科技有限公司为有效推进软件项目管理和开发工作,选择了阿里云云效作为 DevOps 解决方案。通过云效,实现了从 0 开始,到现在近百个微服务、数百条流水线与应用交付的全面覆盖,有效支撑了敏捷开发流程。
19282 30
|
10天前
|
人工智能 自动驾驶 机器人
吴泳铭:AI最大的想象力不在手机屏幕,而是改变物理世界
过去22个月,AI发展速度超过任何历史时期,但我们依然还处于AGI变革的早期。生成式AI最大的想象力,绝不是在手机屏幕上做一两个新的超级app,而是接管数字世界,改变物理世界。
481 49
吴泳铭:AI最大的想象力不在手机屏幕,而是改变物理世界
|
1月前
|
人工智能 自然语言处理 搜索推荐
阿里云Elasticsearch AI搜索实践
本文介绍了阿里云 Elasticsearch 在AI 搜索方面的技术实践与探索。
18839 20
|
1月前
|
Rust Apache 对象存储
Apache Paimon V0.9最新进展
Apache Paimon V0.9 版本即将发布,此版本带来了多项新特性并解决了关键挑战。Paimon自2022年从Flink社区诞生以来迅速成长,已成为Apache顶级项目,并广泛应用于阿里集团内外的多家企业。
17528 13
Apache Paimon V0.9最新进展
|
2天前
|
云安全 存储 运维
叮咚!您有一份六大必做安全操作清单,请查收
云安全态势管理(CSPM)开启免费试用
364 4
叮咚!您有一份六大必做安全操作清单,请查收