Files
Learn-Algorithms/9 Algorithms Job Interview/5 数组数列问题.md
T

694 lines
22 KiB
Markdown
Raw Normal View History

2014-05-05 19:44:01 +08:00
2015-11-28 21:40:11 +08:00
这部分的问题都集中在数据集合上。主要有:
* 数组排序
* top-k
* 子数组
* 多个数组合并,交集
2014-05-06 14:38:24 +08:00
2015-12-05 00:55:44 +08:00
解决这一类问题时,可以从以下几个方面考虑:
2021-08-02 13:27:19 +08:00
* 万能的蛮力穷举
2015-12-05 00:55:44 +08:00
* 散列表空间换事件
* 分治法,然后归并 (归并排序)
* 选择合适的数据结构可以显著提高算法效率 (堆排序求top-k)
* 对无序的数组先排序,使用二分
* 贪心算法或动态规划
2021-08-02 13:27:19 +08:00
## 数组中超过出现次数超过一半的数字
2015-12-05 00:55:44 +08:00
题目:数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字。
`+-1 计数法`
2021-08-02 13:27:19 +08:00
## 找数组里面重复的一个数
2015-12-05 00:55:44 +08:00
找数组里面重复的一个数,一个含n个元素的整数数组至少存在一个重复数,请编程实现,在O(n)时间内找出其中任意一个重复数。
1. hash算法,空间要求多 (注意数组元素要是int类型),数的大小范围和数组长度N都可以是无穷大,这里使用hash算法,空间复杂度是O(n),空间可能无法满足条件。
2. 先排序,复杂度n(logn);然后遍历一遍就可以知道哪些数重复了。
2. 高级解法: 将问题转化为 `判断单链表中存在环`
类似问题:找出数组中唯一的重复元素
2021-08-02 13:27:19 +08:00
## 数组中找出某数字出现的次数
2015-12-05 00:55:44 +08:00
在排序数组中,找出给定数字的出现次数。比如 [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);
```
2021-08-02 13:27:19 +08:00
## 查找最小的k个元素(top-k)
2015-12-05 00:55:44 +08:00
题目:输入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)复杂度。
2021-08-02 13:27:19 +08:00
答案就是`二叉堆`。我们可以遍历总量中的每个元素来跟二叉堆中的堆顶元素比较(堆顶元素在`小根堆`中最小值,在`大根堆`中是最大值),这样在0(1)复杂度就可以完成查找操作,揭下来需要的操作就是重新调整推结构,复杂度是O(logk),因此整个操作复杂度是 `O(n*logk)`
2015-12-05 00:55:44 +08:00
`top-k 小的时候用 *大根堆* ,top-k 大得时候用 *小根堆*`
2021-08-02 13:27:19 +08:00
## 最长公共子序列 (动态规划的经典题目)
2015-12-05 00:55:44 +08:00
【最大/小差问题】
求相邻元素的最大差值,有无序的实数列V[N],要求求里面大小相邻的实数的差的最大值,关键是要求线性空间和线性时间
如 【9,-1,-11,2】 最大差值 = 2-(-11) = 13
最小差 hash合并
最大差 hash分解
桶排序
`桶排序` 比快排还快,最耗空间
2021-08-02 13:27:19 +08:00
## 找出和为m的2个数
2015-12-05 00:55:44 +08:00
2021-08-02 13:27:19 +08:00
输入一个已经按升序排序过的数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。
要求时间复杂度是O(n)。如果有多对数字的和等于输入的数字,输出任意一对即可。
2015-12-05 00:55:44 +08:00
例如输入数组【1、2、4、7、11、15=和数字15。由于4+11=15,因此输出4和11。
2021-08-02 13:27:19 +08:00
2015-12-05 00:55:44 +08:00
```
//返回0找到,返回-1没找到
int findaddends(int *data,int length,int sum,int *a,int *b);
```
分析:
2021-08-02 13:27:19 +08:00
数组升序排列,查找可用二分查找,时间复杂度`O(logn)`,这样问题就变成了找其中一个加数的问题,复杂度为`N*logN`
2015-12-05 00:55:44 +08:00
巧妙解法:数组2端向中间扫描,复杂度O(N)
2021-08-02 13:44:42 +08:00
## 求连续子数组和为m的组合
数组 [2,3,1,2,4,3]求连续子数组sum=7, 结果[1,2,4] [3,4]
* 暴力遍历
* 滑动窗口, 左指针,右指针
```
if sum<k && r<len{
sum+=arr[r]
r++
}else{
sum -= arr[l]
l++
}
```
2015-12-05 00:55:44 +08:00
2021-08-02 13:27:19 +08:00
## 和为m的组合
2015-12-05 00:55:44 +08:00
编程求解:输入两个整数 n 和 m,从数列1,2,3.......n 中 随意取几个数,使其和等于 m ,要求将其中所有的可能组合列出来.
如: n=10,m=25;可能的组合有【】【】【】【】
```
print_sum_detials(int n , int sum)
```
`动态规划`(类似背包问题)
1. 划分问题
2. 选择状态
3. 状态转移方程
4. 规划方程
2021-08-02 13:44:42 +08:00
## 钞票面值100,50,20,10,5,2,1 元,求支付628元最少需要几张钞票
思路: 贪心算法
2015-12-05 00:55:44 +08:00
2021-08-02 13:27:19 +08:00
## 若干个数的和与M最为接近
2015-12-05 00:55:44 +08:00
给定一个实数数组,按序排列(从小到大),从数组从找出若干个数,使得这若干个数的和与M最为接近,描述一个算法,并给出算法的复杂度。
2021-08-02 13:27:19 +08:00
## 递减数列左移后的数组中找数
2015-12-05 00:55:44 +08:00
一个数组是由一个递减数列左移若干位形成的,比如{4,3,2,1,6,5}
是由{6,5,4,3,2,1}左移两位形成的,在这种数组中查找某一个数。
1. 右移,二分查找。 找到最小的数,右移到第一个位置的时候,右移完成 O(N)
2. 直接二分查找
2021-08-02 13:27:19 +08:00
## 求子数组的最大和(最大字段和)
2015-11-28 21:12:00 +08:00
2014-05-05 19:44:01 +08:00
输入一个整形数组,数组里有正数也有负数。
数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
求所有子数组的和的最大值。要求时间复杂度为O(n)。
2015-12-05 00:55:44 +08:00
例如输入的数组为`1, -2, 3, 10, -4, 7, 2, -5` ,和最大的子数组为`3, 10, -4, 7, 2` ,因此输出为该子数组的和18。
2014-05-05 19:44:01 +08:00
2014-05-06 14:38:24 +08:00
1. 蛮力法 fmax(i,j) 找出最大的值,3重循环 ,复杂度 0(n^3)
2014-05-13 09:19:55 +08:00
2. maxendindhere保存当前累加的和,如果<0,就把maxendinghere清零 , max保存最终的最大和
2015-11-28 21:12:00 +08:00
```
2014-05-13 09:19:55 +08:00
int maxSumOfVector(int *data,int length){
int max=0;
int maxendinghere = 0;
if(data==NULL || length<=0){
return 0;
}
for(int i=0;i < length, i++){
maxendinghere+=data[i];
if(maxendinghere<0){
maxendinghere=0;
continue;
}
if(maxendinghere>max){
max=maxendinghere;
}
}
return max;
}
2015-11-28 21:12:00 +08:00
```
2014-05-13 09:19:55 +08:00
2021-08-02 13:27:19 +08:00
## 给出一个洗牌算法
2014-05-13 09:19:55 +08:00
给出洗牌的一个算法,并将洗好的牌存储在一个整形数组里
2021-08-02 13:27:19 +08:00
分析:扑克牌54张`2~10,J,Q,K,A,小王,大王`
2014-05-13 09:19:55 +08:00
1)产生随机数, 随机数 rand()%54 ,rand()每次运行都一样,要改为srand(time(NULL))
2) 遍历数组, 随机数k属于区间[i,n],然后a[i] 和 随机数 a[k] 对换
2021-08-02 13:27:19 +08:00
## 重合区间最长的两个区间段
2015-11-28 21:12:00 +08:00
2014-05-13 09:19:55 +08:00
在一维坐标轴上有n个区间段,求重合区间最长的两个区间段
如【-7,21】,【4,23】,【14,100】,【54,76】
思路一:两两比较,复杂度 N^2
思路二:先排序+分而治之
2021-08-02 13:44:42 +08:00
## 数组分隔成和相等的2个子集
给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等 (eetcode 416, 难度中等)
思路: 动态规划
2021-08-02 13:27:19 +08:00
## 奇偶分离
2015-11-28 21:12:00 +08:00
给定一个存放整数的数组,重新排列数组使得数组左边为奇数,右边为偶数。
2014-05-13 09:19:55 +08:00
要求:空间复杂度O(1),时间复杂度为O(n)
如 [4,5,2,7,5] => [5,7,5,4,2],
空间复杂度O(1),得使用 交换排序
插入排序思想
快速排序思想
1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次.
每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空间,
能否设计一个算法实现?
分析:难点在于 `不用辅助空间`。
2021-08-02 13:27:19 +08:00
思路一: `sum(数组元素的总和)-sum(1~1000)` 得到的差即为重复元素,N较大时注意总和溢出
2014-05-13 09:19:55 +08:00
思路二: 异或操作(位运算)
2021-08-02 13:27:19 +08:00
## 找出数组中两个只出现一次的数字
2015-11-28 21:12:00 +08:00
2014-05-13 09:19:55 +08:00
题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次。
请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
分析:这是一道很新颖的关于位运算的面试题。
1) 任何一个数字异或自己都等于0,如果是只有1个只出现一次的的数字,问题就简单了。
2)
2021-08-02 13:27:19 +08:00
## 用递归的方法判断整数组a[N]是不是升序排列
2014-05-13 09:19:55 +08:00
递归 isAscend(n-1) && a[N-1]< a[N]
在一个int数组里查找这样的数,它大于等于左侧所有数,小于等于右侧所有数。
直观想法是用两个数组a、b。a[i]、b[i]分别保存从前到i的最大的数和从后到i的最小的数,
一个解答:这需要两次遍历,然后再遍历一次原数组,
将所有data[i]>=a[i-1]&&data[i]<=b[i]的data[i]找出即可。
给出这个解答后,面试官有要求只能用一个辅助数组,且要求少遍历一次。
一排N(最大1M)个正整数+1递增,乱序排列,第一个不是最小的,把它换成-1,
最小数为a且未知。求第一个被-1替换掉的数原来的值,并分析算法复杂度。
[4,3,5,2,7,6]
题目啥意思?
正整数序列Q中的每个元素都至少能被正整数a和b中的一个整除,现给定a和b,需要计算出Q中的前几项,例如,当a=3,b=5,N=6时,序列为3,5,6,9,10,12
(1)、设计一个函数void generate(int a,int b,int N ,int * Q)计算Q的前几项
(2)、设计测试数据来验证函数程序在各种输入下的正确性。
分析:
这个输出序列是要 递增排列
思路一: 类似对2各数组merge,取min( A[i],B[j]) .复杂度O(N)
不过这里要注意,去掉 a, b的公倍数。如 3,5 都有15可以整除
2021-08-02 13:27:19 +08:00
## 扑克牌的顺子
2015-11-28 21:12:00 +08:00
2014-05-13 09:19:55 +08:00
从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。
2-10为数字本身,A为1,J为11,Q为12,K为13,而大小王可以看成任意数字。
对这5个数(大小王看做0)
1)排序,如快排
2)统计0的个数
3)统计相邻元素空缺总数
2015-11-28 21:12:00 +08:00
```
//5个是不是顺子
isShunZi(int *a,int length)
```
2014-05-13 09:19:55 +08:00
2021-08-02 13:27:19 +08:00
## n个骰子的点数
2014-05-13 09:19:55 +08:00
把n个骰子扔在地上,所有骰子朝上一面的点数之和为S。
输入n,打印出S的所有可能的值出现的概率。
如n=1,值【1,2,3,4,5,6】每个概率是 1/6
如n=2,值【1~12】 概率。。
2021-08-02 13:27:19 +08:00
## 把数组排成最小的数
2015-11-28 21:12:00 +08:00
2014-05-13 09:19:55 +08:00
题目:输入一个正整数数组,将它们连接起来排成一个数,输出能排出的所有数字中最小的一个。
例如输入数组{32, 321},则输出这两个能排成的最小数字32132。
请给出解决问题的算法,并证明该算法。
2021-08-02 13:27:19 +08:00
## 旋转数组中的最小元素。
2014-05-13 09:19:55 +08:00
题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个排好序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,该数组的最小值为1。
分析:这道题最直观的解法并不难。从头到尾遍历数组一次,就能找出最小的元素,
时间复杂度显然是O(N)。但这个思路没有利用输入数组的特性,我们应该能找到更好的解法。
2021-08-02 13:27:19 +08:00
## 分割数组
2014-05-13 09:19:55 +08:00
2015-11-28 21:12:00 +08:00
一个int数组,里面数据无任何限制,要求求出所有这样的数a[i],其左边的数都小于等于它,右边的数都大于等于它。
能否只用一个额外数组和少量其它空间实现。
`快速排序`
2014-05-13 09:19:55 +08:00
2021-08-02 13:27:19 +08:00
## 约瑟夫环问题
2015-11-28 21:12:00 +08:00
n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始,
2014-05-05 19:44:01 +08:00
每次从这个圆圈中删除第m个数字(第一个为当前数字本身,第二个为当前数字的下一个数字)。
当一个数字删除后,从被删除数字的下一个继续删除第m个数字。
求出在这个圆圈中剩下的最后一个数字。
2021-08-02 13:27:19 +08:00
如 `0,1,2,3,4,5` 删除第2个数字 (n=6,m=2)
2014-05-05 19:44:01 +08:00
第一次删除:1
第二次删除: 3
第三次删除:5
第四次删除:2
因此,左后的一个数字就是 4
2014-05-14 14:54:53 +08:00
从数学上分析下规律:
2021-08-02 13:27:19 +08:00
## 圆形和正方形是否相交
2014-05-05 19:44:01 +08:00
2015-11-28 21:12:00 +08:00
用最简单, 最快速的方法计算出下面这个圆形是否和正方形相交
2014-05-05 19:44:01 +08:00
3D坐标系 原点(0.0,0.0,0.0)
圆形:
半径r = 3.0
圆心o = (*.*, 0.0, *.*)
正方形:
4个角坐标;
1:(*.*, 0.0, *.*)
2:(*.*, 0.0, *.*)
3:(*.*, 0.0, *.*)
4:(*.*, 0.0, *.*)
2014-05-14 14:54:53 +08:00
分析:
2个形状不相交:
2014-05-05 19:44:01 +08:00
2021-08-02 13:27:19 +08:00
## 两个序列和只差最小
2014-05-05 19:44:01 +08:00
有两个序列a,b,大小都为n,序列元素的值任意整数,无序;
要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小。
2015-11-28 21:12:00 +08:00
例如:
```
2014-05-05 19:44:01 +08:00
var a=[100,99,98,1,2, 3];
var b=[1, 2, 3, 4,5,40];
2015-11-28 21:12:00 +08:00
```
2014-05-05 19:44:01 +08:00
2021-08-02 13:27:19 +08:00
## 重新排列使负数排在正数前面
2014-05-05 19:44:01 +08:00
2015-11-28 21:12:00 +08:00
一个未排序整数数组,有正负数,重新排列使负数排在正数前面,并且要求不改变原来的正负数之间相对顺序
2014-05-05 19:44:01 +08:00
2015-11-28 21:12:00 +08:00
比如: input: 1,7,-5,9,-12,15 ans: -5,-12,1,7,9,15 要求时间复杂度O(N),空间O(1)。(此题一直没看到令我满意的答案,一般达不到题目所要求的:时间复杂度O(N),空间O(1),且保证原来正负数之间的相对位置不变)。
2014-05-05 19:44:01 +08:00
updated:设置一个起始点j, 一个翻转点k,一个终止点L
从右侧起
起始点在第一个出现的负数, 翻转点在起始点后第一个出现的正数,终止点在翻转点后出现的第一个负数(或结束)
如果无翻转点, 则不操作
如果有翻转点, 则待终止点出现后, 做翻转, 即ab => ba 这样的操作
翻转后, 负数串一定在左侧, 然后从负数串的右侧开始记录起始点, 继续往下找下一个翻转点
例子中的就是
1, 7, -5, 9, -12, 15
第一次翻转: 1, 7, -5, -12,9, 15 => 1, -12, -5, 7, 9, 15
第二次翻转: -5, -12, 1, 7, 9, 15
N维翻转空间占用为O(1)复杂度是2N;在有一个负数的情况下, 复杂度最大是2N, ;在有i个负数的情况下, 复杂度最大是2N+2i, 但是不会超过2N+N实际的复杂度在O(3N)以内
但从最终时间复杂度分析,此方法是否真能达到O(N)的时间复杂度,还待后续考证。感谢John_Lv,MikovChain。2012.02.25。
1, 7, -5, -6, 9, -12, 15(后续:此种情况未能处理)
1 7 -5 -6 -12 9 15
1 -12 -5 -6 7 9 15
-6 -12 -5 1 7 9 15
更多请参考此文,程序员编程艺术第二十七章:重新排列数组(不改变相对顺序&时间O(N)&空间O(1),半年未被KO)http://blog.csdn.net/v_july_v/article/details/7329314。
2021-08-02 13:27:19 +08:00
## 求最大重叠区间大小
2014-05-05 19:44:01 +08:00
题目描述:请编写程序,找出下面“输入数据及格式”中所描述的输入数据文件中最大重叠区间的大小。
对一个正整数 n ,如果n在数据文件中某行的两个正整数(假设为A和B)之间,即A<=n<=B或A>=n>=B ,则 n 属于该行;
如果 n 同时属于行i和j ,则i和j有重叠区间;重叠区间的大小是同时属于行i和j的整数个数。
例如,行(10 20)和(12 25)的重叠区间为 [12 20] ,其大小为9,行(20 10)和( 20 30 )的重叠区间大小为 1 。
2021-08-02 13:27:19 +08:00
## 四对括号可以有多少种匹配排列方式
2015-11-28 21:12:00 +08:00
比如两对括号可以有两种:()()和(())
2014-05-16 20:11:50 +08:00
2014-05-05 19:44:01 +08:00
2021-08-02 13:27:19 +08:00
## 输出1到最大的N位数
2014-05-05 19:44:01 +08:00
2014-05-13 09:19:55 +08:00
题目:输入数字n,按顺序输出从1最大的n位10进制数。比如输入3,则输出1、2、3一直到最大的3位数即999。
2014-05-05 19:44:01 +08:00
分析:这是一道很有意思的题目。看起来很简单,其实里面却有不少的玄机。
2014-05-13 09:19:55 +08:00
输入4,输出: 1,2,3,。。9999
输入5,输出: 1,2,3,4,...99999
2014-05-05 19:44:01 +08:00
2014-05-13 09:19:55 +08:00
玄机一: 整数溢出
2014-05-05 19:44:01 +08:00
2014-05-13 09:19:55 +08:00
2021-08-02 13:27:19 +08:00
## 和为n连续正数序列
2015-11-28 21:12:00 +08:00
2014-05-13 09:19:55 +08:00
题目:输入一个正数n,输出所有和为n连续正数序列。
例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以输出3个连续序列1-5、4-6和7-8。
print_continuous_sequence_sum(int n)
思路一:枚举法。从1开始一直加到等于n,再从2开始。。一直到 n/2+1,在每一轮,都要逐步比较。复杂度O(N^2)
思路二: a[small,big] sum[small,big]>N small往前移动,否则,big往前移动。 O(N)复杂度搞定
2021-08-02 13:27:19 +08:00
## 找出和为N+1的2个数
2014-05-13 09:19:55 +08:00
一个整数数列,元素取值可能是1~N(N是一个较大的正整数)中的任意一个数,相同数值不会重复出现。
2021-08-02 13:27:19 +08:00
设计一个算法,找出数列中符合条件的数对的个数,满足数对中两数的和等于`N+1`。
复杂度最好是`O(n)`,如果是 `O(n2)`则不得分。
2014-05-13 09:19:55 +08:00
2021-08-02 13:27:19 +08:00
分析:列出所有的数对,如输入15,输出`【1,14】【2,13】【3,12】。。。`
2014-05-13 09:19:55 +08:00
2015-11-28 21:12:00 +08:00
```
2014-05-13 09:19:55 +08:00
int print_sequence_sum(int n)
2015-11-28 21:12:00 +08:00
```
2014-05-05 19:44:01 +08:00
2014-05-13 09:19:55 +08:00
2021-08-02 13:27:19 +08:00
## 寻找丑数
2015-11-28 21:12:00 +08:00
2014-05-13 09:19:55 +08:00
题目:我们把只包含因子2、3和5的数称作丑数(Ugly Number)。
例如6、8都是丑数,但14不是,因为它包含因子7。习惯上我们把1当做是第一个丑数。
求按从小到大的顺序的第1500个丑数。
2014-05-05 19:44:01 +08:00
2014-05-13 09:19:55 +08:00
分析:这是一道在网络上广为流传的面试题,据说google曾经采用过这道题。
这里的因子应该不包含本身,因此这个序列应该是这样:
1,2,3,4,5,6,8,9,10,12,15,16,18,20,28....
2014-05-05 19:44:01 +08:00
2015-11-28 21:12:00 +08:00
1)所有的偶数都在序列中
2)3的倍数也在序列中
3)5的倍数也在系列中
0. 2,3,5最小公倍数是30
1. [1,30]符合条件有22个
2. [30,60]符合条件也22个
第1500个: 1500/22=68余4,一个周期内的前4个数是2,3,4,5; 最终答案是`68*30+5`
2014-05-05 19:44:01 +08:00
2021-08-02 13:27:19 +08:00
## 调整数组顺序使奇数位于偶数前面
2015-11-28 21:12:00 +08:00
2014-05-05 19:44:01 +08:00
题目:输入一个整数数组,调整数组中数字的顺序,使得所有奇数位于数组的前半部分,
所有偶数位于数组的后半部分。要求时间复杂度为O(n)。
2014-05-13 09:19:55 +08:00
思路:两边向中间扫描,如果第一个指针是偶数,第二个指针是奇数,就交换;如果第一个是偶数,第二个也偶数,第二个指针向前移;反之,第一个指针向后移
2015-11-28 21:12:00 +08:00
```
2014-05-13 09:19:55 +08:00
void reorder(int *data, int length);
2015-11-28 21:12:00 +08:00
```
2015-11-28 21:40:11 +08:00
2014-05-05 19:44:01 +08:00
2021-08-02 13:27:19 +08:00
## 在从1到n的正数中1出现的次数
2015-11-28 21:12:00 +08:00
题目:输入一个整数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. 分析规律
2014-05-05 19:44:01 +08:00
2015-11-28 21:12:00 +08:00
2021-08-02 13:27:19 +08:00
## 求一个数组的最长递减子序列
2015-11-28 21:12:00 +08:00
2021-08-02 13:27:19 +08:00
比如`{9,4,3,2,5,4,3,2}`的最长递减子序列为`{9,5,4,3,2}`
2014-05-05 19:44:01 +08:00
2014-05-13 09:19:55 +08:00
`动态规划`
2021-08-02 13:27:19 +08:00
## 如何求2个集合的交集
2014-05-14 14:54:53 +08:00
1.每个集合里面是否有重复元素?
思路一:hash,复杂度O(M+N)
2021-08-02 13:27:19 +08:00
## 两两之差绝对值最小的值
2014-05-13 09:19:55 +08:00
有一个整数数组,请求出两两之差绝对值最小的值,记住,只要得出最小值即可,不需要求出是哪两个数。
2014-05-07 11:24:51 +08:00
如 [-1, 3, 5, 9] 绝对值最小的是2(5-3)
2014-05-13 09:19:55 +08:00
2014-05-07 11:24:51 +08:00
最短区间问题
如果是有重复元素,那最小值就是0了
2014-05-13 09:19:55 +08:00
解题思路: 可以将这个问题转化为 ”求最大字段和“ 问题。。。
2014-05-07 11:24:51 +08:00
2021-08-02 13:27:19 +08:00
## 数值是否连续相邻
2014-05-05 19:44:01 +08:00
2014-05-13 09:19:55 +08:00
一个整数数列,元素取值可能是0~65535中的任意一个数,相同数值不会重复出现。0是例外,可以反复出现。请设计一个算法,当你从该数列中随意选取5个数值,判断这5个数值是否连续相邻。
2014-05-05 19:44:01 +08:00
注意:
- 5个数值允许是乱序的。比如: 8 7 5 0 6
- 0可以通配任意数值。比如:8 7 5 0 6 中的0可以通配成9或者4
- 0可以多次出现。
- 复杂度如果是O(n2)则不得分。
2014-05-13 09:19:55 +08:00
这个问题跟”扑克牌顺子“判断问题一样,通过比较0的个数和相邻数字之间间隔总和来判断所有数是否连续。
2014-05-05 19:44:01 +08:00
2014-05-06 14:38:24 +08:00
2021-08-02 13:27:19 +08:00
## 最长递增子序列
2015-11-28 21:12:00 +08:00
2014-05-05 19:44:01 +08:00
题目描述:设L=<a1,a2,…,an>是n个不同的实数的序列,L的递增子序列是这样一个子序列
2014-05-13 09:19:55 +08:00
Lin=< aK1,ak2,…,akm >,其中k1< k2<…< km且aK1< ak2<…< akm。
2014-05-05 19:44:01 +08:00
求最大的m值。
2014-05-13 09:19:55 +08:00
如【5,6,7,3,2,8】 最长子序列 【5,6,7,8】
2014-05-05 19:44:01 +08:00
2014-05-13 09:19:55 +08:00
`动态规划`
2021-08-02 13:27:19 +08:00
## Fibonacci数列
2014-05-13 09:19:55 +08:00
2015-11-28 21:12:00 +08:00
题目:定义Fibonacci数列如下:
/ 0 n=0
f(n)= 1 n=1
/ f(n-1)+f(n-2) n=2
2014-05-13 09:19:55 +08:00
2015-11-28 21:12:00 +08:00
输入n,用最快的方法求该数列的第n项。
2014-05-13 09:19:55 +08:00
2015-11-28 21:12:00 +08:00
虽然fibonacci数列是`递归`的经典应用,但递归效率很差,会有很多重复的计算,复杂度是成指数递增的,我测试了下计算50的时候已经要300s了。
2014-05-13 09:19:55 +08:00
2015-11-28 21:12:00 +08:00
思路二:从下往上计算,复杂度O(N),一个循环就搞定
2014-05-13 09:19:55 +08:00
2015-11-28 21:12:00 +08:00
思路三: logN
2014-05-07 11:24:51 +08:00
2021-08-02 13:27:19 +08:00
## 一个整数数组,长度为n,将其分为m份,使各份的和相等,求m的最大值
2015-11-28 21:40:11 +08:00
比如{3,2,4,3,6} 可以分成{3,2,4,3,6} m=1;
{3,6}{2,4,3} m=2
{3,3}{2,4}{6} m=3 所以m的最大值为3
////////////// 数列 ///////////////
输入a1,a2,...,an,b1,b2,...,bn,
在O(n)的时间,O(1)的空间将这个序列顺序改为a1,b1,a2,b2,a3,b3,...,an,bn,
且不需要移动,通过交换完成,只需一个交换空间。
例如,N=9时,第2步执行后,实际上中间位置的两边对称的4个元素基本配对,
只需交换中间的两个元素即可,如下表所示。颜色表示每次要交换的元素,左边向右交换,右边向左交换。
交换过程如下表所示
交换x1,x3;交换x2,x4;再交换中间的x1,x4;交换y1,y2。
给你10分钟时间,根据上排给出十个数,在其下排填出对应的十个数
要求下排每个数都是先前上排那十个数在下排出现的次数。
上排的十个数如下:
【0,1,2,3,4,5,6,7,8,9】
初看此题,貌似很难,10分钟过去了,可能有的人,题目都还没看懂。
举一个例子,
数值: 0,1,2,3,4,5,6,7,8,9
分配: 6,2,1,0,0,0,1,0,0,0
0在下排出现了6次,1在下排出现了2次,
2在下排出现了1次,3在下排出现了0次....
以此类推..
0xX0+1xX1+2xX2....+9xX9 = 10;
X0+X1+...+ = 10;
转换成多元一次方程求通解的问题。(Matlib)
给出两个集合A和B,其中集合A={name},
集合B={age、sex、scholarship、address、...},
要求:
问题1、根据集合A中的name查询出集合B中对应的属性信息;
问题2、根据集合B中的属性信息(单个属性,如age<20等),查询出集合A中对应的name。
2014-05-07 11:24:51 +08:00