176 lines
5.3 KiB
Markdown
176 lines
5.3 KiB
Markdown
# 数列-查找
|
||
|
||
|
||
## 数组中超过出现次数超过一半的数字
|
||
|
||
题目:数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字。
|
||
|
||
`+-1 计数法`
|
||
|
||
|
||
|
||
## 找数组里面重复的一个数
|
||
|
||
找数组里面重复的一个数,一个含n个元素的整数数组至少存在一个重复数,请编程实现,在O(n)时间内找出其中任意一个重复数。
|
||
|
||
1. hash算法,空间要求多 (注意数组元素要是int类型),数的大小范围和数组长度N都可以是无穷大,这里使用hash算法,空间复杂度是O(n),空间可能无法满足条件。
|
||
2. 先排序,复杂度n(logn);然后遍历一遍就可以知道哪些数重复了。
|
||
2. 高级解法: 将问题转化为 `判断单链表中存在环`
|
||
|
||
|
||
类似问题:找出数组中唯一的重复元素
|
||
|
||
|
||
## 查找只出现一次的元素
|
||
|
||
给一个非空整数数组,比如 [2, 2, 3] ,其余元素均出现2次,找出那个只出现一次的元素。
|
||
|
||
思路: 异或运算,成对儿的数字就会变成 0,落单的数字和 0 做异或还是它本身
|
||
|
||
```
|
||
int singleNumber(vector<int>& nums) {
|
||
int res = 0;
|
||
for (int n : nums) {
|
||
res ^= n;
|
||
}
|
||
return res;
|
||
}
|
||
```
|
||
|
||
|
||
## 数组中找出某数字出现的次数
|
||
|
||
在排序数组中,找出给定数字的出现次数。比如 [1, 2, 2, 2, 3] 中2的出现次数是3次。
|
||
|
||
分析:
|
||
1. 因为是排序数组,可以使用二分查找
|
||
2. 将二分查找坚持到底,这样在最坏的情况下([2,2,2,2,2,2,2])都有0(lgn)复杂度
|
||
|
||
```
|
||
int binary_search_first(int *a,int length,int key);
|
||
int binary_search_lash(int *a,int length,int key);
|
||
```
|
||
|
||
|
||
|
||
|
||
## 大于K的最小正整数
|
||
|
||
给定一个集合A=[0,1,3,8](该集合中的元素都是在0,9之间的数字,但未必全部包含),指定任意一个正整数K,请用A中的元素组成一个大于K的最小正整数。
|
||
|
||
比如,A=[1,0] K=21 那么输出结构应该为100。
|
||
|
||
|
||
|
||
|
||
|
||
## 查找最小的k个元素(top-k)
|
||
|
||
题目:输入n个整数,输出其中最小的k个。
|
||
例如输入1,2,3,4,5,6,7和8这8个数字,则最小的4个数字为1,2,3和4。
|
||
|
||
```
|
||
topMinK(int *a,int length,int k);
|
||
topMaxK(int *a,int length, int k);
|
||
```
|
||
|
||
|
||
1. 全部排序 复杂度 NlogN , 数据了较大时,内存可能承受不住
|
||
2. 部分排序 维护一个大小为K的数组,由大到小排序,然后遍历所有数据,每个数据跟数组中最小元素比较,如果比最小元素大,就要插入数组了,这里还有寻找插入位置,移动数组元素的cpu消耗。复杂度是N*K
|
||
3. 堆排序 。在这的K较大时(比如这道题目:2亿个整数中求最大的100万之和),上面的算法还是有很多可以改进的地方,如采用二分查找定位插入位置,移动数组元素的计算是躲不过去了。那有没有什么数据结构即能`快速查找,还能快速移动元素`呢?最好是O(1)复杂度。
|
||
|
||
答案就是`二叉堆`。我们可以遍历总量中的每个元素来跟二叉堆中的堆顶元素比较(堆顶元素在`小根堆`中最小值,在`大根堆`中是最大值),这样在0(1)复杂度就可以完成查找操作,揭下来需要的操作就是重新调整推结构,复杂度是O(logk),因此整个操作复杂度是 `O(n*logk)`
|
||
|
||
|
||
`top-k 小的时候用 *大根堆* ,top-k 大得时候用 *小根堆*`
|
||
|
||
|
||
## 找第k大的数
|
||
|
||
比如 1,2,3,4,5,6,7和8这8个数字,低3大的数字是 6
|
||
|
||
```
|
||
int topK(int * a, int length, int k)
|
||
```
|
||
|
||
|
||
|
||
## 最长公共子序列 (动态规划的经典题目)
|
||
|
||
【最大/小差问题】
|
||
求相邻元素的最大差值,有无序的实数列V[N],要求求里面大小相邻的实数的差的最大值,关键是要求线性空间和线性时间
|
||
|
||
如 【9,-1,-11,2】 最大差值 = 2-(-11) = 13
|
||
|
||
最小差 hash合并
|
||
最大差 hash分解
|
||
桶排序
|
||
|
||
`桶排序` 比快排还快,最耗空间
|
||
|
||
|
||
|
||
|
||
|
||
## 最长递增子序列
|
||
|
||
题目描述:设L=<a1,a2,…,an>是n个不同的实数的序列,L的递增子序列是这样一个子序列
|
||
Lin=< aK1,ak2,…,akm >,其中k1< k2<…< km且aK1< ak2<…< akm。
|
||
求最大的m值。
|
||
|
||
如【5,6,7,3,2,8】 最长子序列 【5,6,7,8】
|
||
|
||
`动态规划`
|
||
|
||
|
||
|
||
|
||
|
||
## 在从1到n的正数中1出现的次数
|
||
|
||
题目:输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数。
|
||
|
||
例如输入12,从1到12这些整数中包含1 的数字有1,10,11和12,1一共出现了5次。
|
||
分析:这是一道广为流传的google面试题。
|
||
```
|
||
int one_appear_count(int n);
|
||
```
|
||
|
||
思路1. 遍历`1~n`,统计出现1的个数;n足够大时,效率很低
|
||
思路2. 分析规律
|
||
|
||
|
||
|
||
## 搜索旋转排序数组
|
||
|
||
|
||
整数数组 nums 按升序排列,数组中的值 互不相同 。
|
||
|
||
在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。
|
||
|
||
给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。
|
||
|
||
|
||
示例 1:
|
||
|
||
```
|
||
输入:nums = [4,5,6,7,0,1,2], target = 0
|
||
输出:4
|
||
```
|
||
|
||
示例 2:
|
||
```
|
||
输入:nums = [4,5,6,7,0,1,2], target = 3
|
||
输出:-1
|
||
```
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|