IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 剑指offer:数组中重复的数字 -> 正文阅读

[数据结构与算法]剑指offer:数组中重复的数字

剑指offer:数组中重复的数字

题目一:找出数组中任意一个重复的数字

问题描述

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

输入输出

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

算法描述

方法一:预排序 + 扫描一遍

先把输入的数组排序。从排序的数值中找出重复的数字,只需要和相邻的数字进行比较是否相等,扫描一遍即可。

算法分析
  • 时间复杂度:O(nlgn)
  • 空间复杂度:O(1)

方法二:哈希表

从头到尾扫描数组的每个数字,每扫描到一个数字,判断哈希表里是否已经包含了这个数字。如果哈希表里没有包含这个数字,就将它加入哈希表中。

算法分析
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

方法三:原地重排

注意到数组中的数字都在0~n-1的范围内。如果这个数组没有重复的数字,那么数字i就会对于下标i的位置;如果有重复数字,必然发生冲突。可以利用数字范围大小的特点,直接在原地重排。

思路:从头到尾依次扫描这个数组中的每个数字。当扫描到下标为i的数字时,首先判断数字是否等于i:

  • 如果相等,继续下一个下标位置;
  • 如果不相等,设numbers[i]=value,需和numbers[value]进行比较
    • 如果相等,则说明之前已经有值为i的数字出现,所以有重复
    • 如果不想等,交换这两个数numbers[value]和numbers[i]。(注意交换后,下标为i的位置仍然要继续判断)
算法分析
  • 时间复杂度O(n)

  • 空间复杂度O(1)

具体代码如下:
bool duplicate(int numbers[],int length,int* duplication){
	if(numbers == nullptr || length < 0){
		return false;
	}

	for(int i = 0;i<length;i++){
		if(numbers[i]<0||numbers[i]>length-1)
			return false;
	}

	for(int i = 0;i<length;i++){
		while(numbers[i]!=i){
			if(numbers[i]!=numbers[numbers[i]]){
				// swap(numbers[i],numbers[numbers[i]])
				int t = numbers[i];
				numbers[i] = numbers[numbers[i]];
				numbers[numbers[i]] = t;
			}
			else 
				*duplication = numbers[i];
			return true;
		}
	}
	return false;
}

题目二:不修改数组找出数组中任意一个重复的数字

问题描述

在一个长度为n+1的数字中,所有的数字都在1~n的范围内,所以数组至少有一个数字是重复的。请找出数组中任意一个重复的数字,但不能修改输入的数组。

算法描述

方法一:

利用题目一的方法二 或 创建一个辅助数组,利用题目一的方法三修改辅助数组

算法分析
  • 时间复杂度O(n)

  • 空间复杂度O(n)

方法二:

我们把从1~ n 的数字从中间的数字middle分为两部分,前面一半为1 ~ middle,后面一半为middle + 1 ~ n。统计[1,middle]这个区间的整数在整个数组中出现的次数

  • 如果次数超过m,那么该区间里一定包含了重复数字,则检验的数组目标就可以从[start,end]转变为[start,middle],即end = middle
  • 否则,后一半的区间里一定包含了重复数字,则检验的数组目标就可以从[start,end]转变为[middle+1,end],即start = middle + 1

缩小了待检验区间的长度后,继续分两部分,直到找到一个重复的数字。整个过程类似二分查找。

算法分析
  • 时间复杂度O(nlgn)

  • 空间复杂度O(1)

具体代码
int getDuplication(const int* numbers,int length){
	if(numbers == nullptr || length <= 0)
		return -1;
	int start = 1;
	int end = length-1;
	while(end >= start){
		middle = (end-start)>>1 + start;
		int count = countRange(numbers,length,start,middle);
		if(end == start){
			if(count >1)
				return start;		//返回重复的数字
			else
				break;
		}	
		if(count > (middle-start+1))
			end = middle;		//该区间start ~ middle中,有重复的数字,所以可以缩小区间范围从[start,end]变成[start,middle]
		else
			start = middle +1;	//该区间start ~ middle中,没有重复的数字,则看后半区间
		
	}
	return -1;
}

int countRange(int* numbers,int length,int start,int end){
	if(numbers == nullptr)
		return 0;
	int count = 0;
	for(int i = 0;i<length;i++){
		if(numbers[i]>=start && numbers[i]<=end)
			count++;
	}
	return count;

}

参考资料:剑指offer 2.3.1 数组 面试题3:数组中重复的数字

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-10-03 17:18:25  更:2021-10-03 17:20:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 4:34:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码