大数据
Map-Reduce 和Hadoop 逐渐成为面试热门
1. 介绍哈希函数
哈希函数又叫散列函数 1.1 典型的哈希函数都有无限的输入值域。 1.2 输入值相同时,返回值一样。 1.3 输入值不同时,返回值可能一样,也可能不一样 1.4 不同输入值得到的哈希值,整体均分的分布在输出域S上(重要) 1~3 点性质是哈希函数的基础,第4点是评价一个哈希函数优劣的关键。 aaa1 aaa2 aaa3 虽然相似,但哈希值差异巨大。
2.介绍Map-Rdeduce
2.1 Map阶段 把大任务分成子任务 2.2 Reduce阶段 子任务并发处理,然后合并结果。
难点:工程上的处理
注意点:
1. 备份的考虑,分布式存储的设计细节,以及容灾策略。 2. 任务分配策略与任务进度跟踪的细节设计,节点状态的呈现 3. 多用户权限的控制
map-reduce 方法统计文章的单词
文章-> 预处理
1.去掉标点符号 2.连字符 3.对于缩写的处理 4.大小写的处理
对每个单词生成词频为1
哈希函数
子任务进行处理
海量数量处理技巧
- 分而自治,通过哈希函数将大任务分流到机器或分流秤小文件
- 常用hashMap 或bitamp
难点:通讯、时间和空间的估算。
- 请对10亿个IPV4的ip地址进行排序,每个ip只会出现一次。
普通做法:
ip-转换为无符号整数 10亿个整数 4G
推荐做法:
bitmap 2^32 bit类型的数组。
每个位置上是一个bit,只能表示0和1两种状态。
长度为2^32的bit数组,空间约为128m.
-
请对10亿人的年龄进行排序
0~200
计数排序 -
20亿全是32位数整数的文件,空间限制大小2G
hashmap记录所有出现的次数
key->具体某一种数
value-> 这种数出现的次数
内存可能超出
文件分流
在40亿个无符号整数的文件,所以在整个范围中必然没有出现过的数,可以使用最多10M的内存,只用找到一个没有出现过的数即可,该如何找?
hash 表 40亿条 每一条4个字节 16G
bitmap 500M
64个区间
500M/64 8M
1、根据内存限制决定区间大小,根据区间大小,得到有多少个变量,来记录每个区间的数出现的次数。
2、 统计区间上的数的出现次数,找到不足的区间。
3、利用bitmap对不满足的区间,进行这个区间上的数的词频统计。
百亿数据中,找到100个热词
分流 确定机器数
对每一个机器,进行文件分流,小根堆 确定top100
工程师使用服务器集群来设计和是吸纳数据缓存,以下是常见的侧脸。
- 无论是添加、查询还是删除数据,都先将数据的id通过哈希函数转换成一个哈希值,记为key.
2.如果目前机器有N台,则计算key%N的值,这个值就是该数据所属的机器编号,无论是添加、删除还是查询操作,都只在这台机器上进行。请分析这种缓存策略可能带来的问题。并提出改进的方案。
如果增加或删除机器,数据迁移的代价很大。
一致性哈希算法
数据id—> 0~ 2 ^32
key 和data 相邻存储
顺时针进行
动态规划
给定数组arr,arr中所有的值杜伟整数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个整数aim代表要找的钱数,求换钱有多少种方法.
暴力搜索方法
记忆搜索方法
动态规划方法
状态继续优化
arr={5,10,25,1} aim={1000}
- 暴力搜索解决:
public int coins1(int[] arr,int aim){ if(arr==null||arr.length==0||aim<0) { return 0; } return process1(arr,0,aim); } public int process1(int [] arr,int index,int aim){ int res=0; if(index==arr.length){ res=aim==0?1:0; }else{ for(int i=0;arr[index]*i<=aim;i++){ res+=process1(arr,index+1,aim-arr[index]*i); } } }
如果已经使用0张5元和1张10元的情况下
后续将求:p1(arr,2,990)
这里2表示arr剩下的钱为arr[2,3] 即为[25,1]
990:表示要找的剩余钱数。
2张5元0张10元p1(arr,2,990)
-
记忆搜索方法:
arr={5,10,24,1}, aim=1000
p(index,aim) 结果表map-
每计算完一个p(index,aim),都将结果放入map中,index和aim组成共同的key,
返回结果为Value. -
要进入一个递归过程p(index,aim)
先以index和aim注册的key在map中查询是否已经在value中,如果存在,则直接取值,如果不存在,才进行递归计算。
-
public int coins2(int[] arr,int aim){ if(arr==null||arr.length==0||aim<0){ return 0; } int[][] map=new int[arr.length+1][aim+1]; return process2(arr,0,aim,map); } public int process2(int[] arr,int index,int aim,int[][] map){ int res=0; if(index==arr.length){ res=aim==0?1:0; }else{ int mapValue=0; for(int i=0;arr[index]*i<=aim;i++){ mapValue=mapValue==-1?0:mapValue; }else{ res+=process2(arr,index+1,aim-arr[index]*i,map); } } } map[index][aim]=res==0?-1:res; return res; }
-
动态规划方法
如果arr长度为N,生成行数为N,列数为aim+1的矩阵dp
dp[i][j] 的含义是在使用arr[0..i]货币的情况下,有多少种方法。
什么是动态规划方法
-
其本质是利用空间来记录每一个暴力搜索的计算结果的时候直接使用,从而不再是用重复计算。
-
动态规划由于规定了每一种递归的计算顺序,依次进行计算。
面试中遇到暴力递归题目可以优化成动态规划方法的大体过程:
- 实现暴力递归方法。
- 在暴力搜索方法的函数中看看那些参数可以代表递归过程。
- 找到代表递归过程的参数之后,记忆话搜索方法非常容易实现。
- 通过分析记忆话搜索的依赖路径,进而实现动态规划。
- 根据记忆化搜索方法改出动态规划,减少时间复杂度。
动态规划的关键点:
-
最优化原理,也就是最优子结构性质。这指的是一个最优化策略具有这样的性质,不论过去状态和决策如何,对前面的决策所形成的的状态而言,余下的诸多决策必须构成最优决策,简单来说就是一个最优化的策略的子策略总是最优的,如果一个问题满足最优化原理,就称其具有最优子结构性质。
-
无后效性。指的是某状态下决策的收益,只与状态和决策相关,与到达该状态的方式无关。
-
子问题的重叠性,动态规划将原来具有指数级时间复杂度的暴力搜索算法改进成了具有多项式时间复杂度的算法。其中的关键在于解决冗余,这是动态规划算法的根本目的。
经典动态规划的问题
-
有n级台阶,一个每次上一级或者两级,问有多少种走完n级的方法?
f(1)=1
f(2)=2
f(i)= f(i-1)+f(i-2)
public int s1(int n){ if(n<1) return 0; } if(n==1||n==2){ return n; } return s1(n-1)+s1(n-2); }
-
求矩阵中最小的路径和
dp[i][j]=m[i][j]+dp[i-1][j]
dp[i][j-1] -
返回arr的最长递增子序列长度
2 1 5 3 6 4 8 9 7
返回 1 3 4 8 9 长度为5arr 2 1 5 3 6 4 8 9 7
dp: 1 1 2 2 3 3 4 5 4 长度为5 -
假设str1的长度为M,str2的长度为N,生成大小为M*N的矩阵dp.dp[i][j]的含义是str1[0..i] 与str2[0..j]的最长公共序列的长度。
待补:
-
一个背包有一定的承重W,有N件物品,每件都有自己的价值,记录在数组V中,也都有自己的重量,记录在数组W中,没见物品只能选择要装入背包还是不装入背包,要求在不超过背包承重的前提下,选出物品的总价值最大。
假设物品编号1~n,一件一件物品考虑是否加入背包
假设dp[x][y]表示前X件物品,不超过重量y的时候的最大价值。枚举一下第X件物品的情况。
情况一: 如果选择第X件物品,则前X-1件物品得到的重量不能超过y-w[x].
情况二:如果不选第X件物品,则前X-1件物品得到的重量不能超过所以dp[x][y]可能等于dp[x-1][y],也就是是不取第x件物品的时候,价值和之前一样。 也可能是dp[x-1][y-w[x]]+v[x], 也就是决定拿第x件物品的情况,当然会获得x物品的价值。 两种可能性中,应该选择价值最大的那个。dp[x][y]=max{dp[x-1][y],dp[x-1][y-w[x]]+v[x]}. 对于dp矩阵来说,行数是物品的数量n,行数是背包的重量W。从左到右,再从上到下依次计算所有dp值即可。