Files
Learn-Algorithms/9 Algorithms Job Interview/5.4 数列-查找.md
T
2021-11-14 22:42:14 +08:00

176 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 数列-查找
## 数组中超过出现次数超过一半的数字
题目:数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字。
`+-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
```