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

Posted yantuguiguziPGJ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指 Offer(第 2 版)刷题 | 03. 数组中重复的数字相关的知识,希望对你有一定的参考价值。

目录

 

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

我的解法:

(1)排序算法

插入排序

希尔排序

(2)相邻比较大小


题目 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++排序算法代码汇总

 

以上是关于剑指 Offer(第 2 版)刷题 | 03. 数组中重复的数字的主要内容,如果未能解决你的问题,请参考以下文章

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

剑指 Offer(第 2 版)刷题 | 05. 替换空格

剑指 Offer(第 2 版)刷题 | 04. 二维数组中的查找

剑指 Offer(第 2 版)完整题解笔记 & C++代码实现(LeetCode版)

剑指 Offer(第 2 版)完整题解笔记 & C++代码实现(LeetCode版)

剑指offer第二版和专项突击版有啥区别