综述:数据结构和算法是高级前端的必备知识,贵在总结,坚持积累
1.将数据中的数据转成树状结构,实现前缀树trie,思考前缀树trie和tree之间的不同?
var transObject = function(tableData,keys){
let hashTable = {}, res = []
for (let i = 0; i < tableData.length; i++) {
let arr = res, cur = hashTable
for (let j = 0; j < keys.length; j++) {
let key = keys[j], filed = tableData[i][key];
if (!cur[filed]) {
let pusher = {value:filed},tmp;
if (j !== (keys.length - 1)){
tmp = [];
pusher.children = tmp
}
cur[filed] ={$$pos: arr.push(pusher) - 1 };
cur = cur[filed];
arr = tmp;
} else {
cur = cur[filed];
arr = arr[cur.$$pos].children
}
}
}
return res
};
var data = [{
"province": "浙江",
"city": "杭州",
"name": "西湖"
}, {
"province": "四川",
"city": "成都",
"name": "锦里"
}, {
"province": "四川",
"city": "成都",
"name": "方所"
}, {
"province": "四川",
"city": "阿坝",
"name": "九寨沟"
}];
var keys = ['province', 'city', 'name'];
console.log(transObject(data, keys));
2.使用js方法遍历html结构?收集所有的标签,使用数组存储所有的标签?
基础信息
3.redux的使用,最简单的demo
function inc() {
return { type: 'INCREMENT' };
}
function dec() {
return { type: 'DECREMENT' };
}
function add10() {
return { type: 'ADD10' };
}
function reducer(state, action) {
// 首次调用本函数时设置初始 state
state = state || { counter: 0 }; //这里是存储的数据值
switch (action.type) {
case 'INCREMENT':
return { counter: state.counter + 1 };
case 'DECREMENT':
return { counter: state.counter - 1 };
case 'ADD10':
return { counter: state.counter+10};
default:
return state; // 无论如何都返回一个 state
}
}
var store = Redux.createStore(reducer);
console.log( store.getState() ); // { counter: 0 }
store.dispatch(inc());
console.log( store.getState() ); // { counter: 1 }
store.dispatch(inc());
console.log( store.getState() ); // { counter: 2 }
store.dispatch(dec());
console.log( store.getState() ); // { counter: 1 }
store.dispatch(add10());
console.log( store.getState() ); // { counter: 1 }
4.斐波那契数列,1,1,2,3,5,8......后一个数字是前两个数字之和?要使用动态规划的方法来实现,不然算法的时间复杂度太高。使用数组缓存上一次计算的结果才对。
/**
*time/author:2019/5/14 "mouyao"
*desc:递归实现
*/
console.time("递归");
var feibo=function(n){
if(n<2){
return 1;
}else{
return feibo(n-1) + feibo(n-2);
//return arguments.callee(n-1)+arguments.callee(n-2);
}
};
console.log(feibo(20));
console.timeEnd("递归");
/**
*time/author:2019/5/14 "mouyao"
*desc: 直接使用加法,使用for循环实现数字的多次叠加
*/
console.time("加法实现斐波那契数列");
function fibo(n){
if (n < 2) {
return 1;
}
var a = 1, b = 1,c=0;
for (var i = 2; i <= n - 1 ;i++ ) {
c=a+b;
a=b;
b=c;
}
return a + b;
}
console.log(fibo(20));
console.timeEnd("加法实现斐波那契数列");
/**
*time/author:2019/5/14 "mouyao"
*desc:非递归实现,数组缓存,这种方法在调用多次的时候,非常值得推荐,在明源云中,就存在大数据计算的缓存问题,这种思想十分值得分析,将所有的计算结果保存到函数中的数组中,后期
*/
console.time("数组缓存");
var IterMemoFib = function() {
var cache = [1, 1];
return function (n) {
if (n >= cache.length) {
for (var i = cache.length; i
5.爬梯子问题,1,2,3,5,8,9。。。。和第4题十分的相似,分别的代码如下。这里也要使用动态规划的思想来解决问题,缓存上一次的计算结果才对。
// 爬梯子问题
var climbStairs = function(n) {
if(n===1||n===2||n===3){
return n;
}else if(n>3){
return climbStairs(n-2)+climbStairs(n-1);
return arguments.callee(n-2)+arguments.callee(n-1);
}
};
console.log(climbStairs(45));
6.实现两个大数相加,这两个大数有可能会超出存储空间,该怎样来实现(腾讯前端面试题目),实现两个大位数的相乘,想法几乎是一样的。
首先说明JavaScript中虽然是一门弱类型语言,其实Number类型的数据也是有存储范围的。其最大最小的存储范围是
最大安全数: Math.pow(2, 53) - 1 // 9007199254740991
最小安全数:Math.pow(-2, 53) + 1 // -9007199254740992
超出这个范围的运算都是不安全的,可以对这样的数据进行操作测试
7.前端大厂数据结构和算法面试题汇总,十个非常经典的问题,值得细细品味
https://zhuanlan.zhihu.com/p/57200821
8.排序算法实现(二叉树排序> 快速排序 >冒泡排序),一共有始终排序方法。
//产生一个测试数组
function makeRandomNumber(){
var arr=[];
for(var i=0;i<99999;i++){
arr.push(Math.ceil(Math.random()*i));
}
return arr;
}
/**
*time/author:2019/5/7 "mouyao"
*desc:快排序实现思路,选择一个数字为基准,将数字分成比他大和小的两个部分,递归排序
* 拆分后的两个数字,直到数组长度为1为止,效率很高,当数据量很小的时候,看不出性能差异,
* 当数据量为99999时,时间差了30多倍
*/
console.time("快排序");
var arr=makeRandomNumber();
function quickSort(arr){
var leftArr=[];
var rightArr=[];
var middleValue=arr[0];
if(arr.length<=1){
return arr;
}else{
for(var i=1;imiddleValue){
leftArr.push(arr[i]);
}else{
rightArr.push(arr[i]);
}
}
}
//return [].concat(quickSort(leftArr),middleValue,quickSort(rightArr));
return quickSort(leftArr).concat(middleValue,quickSort(rightArr));
}
console.log(quickSort(arr));
console.timeEnd("快排序"); //725ms
/**
*time/author:2019/5/7 "mouyao"
*desc:冒泡排序实现,选择第一个数字为基准,分别遍历,如果比他大,则交换两个值,如果小,则不交换
*/
var arr=makeRandomNumber();
console.time("冒泡排序");
function bubblingSort(arr){
for(var i=0;iarr[j]){
[arr[i],arr[j]]=[arr[j],arr[i]];
}
}
}
return arr;
}
console.log(bubblingSort(arr));
console.timeEnd("冒泡排序");//19055ms
var arr=makeRandomNumber();
console.time("二叉树排序");
function BinaryTree(){
var Node=function(key){
this.key=key;
this.left=null;
this.right=null;
};
var root=null; //二叉树数据结构的值存储到这里
var insertNode=function(node,newNode){
if(newNode.key=99999){
console.log(newArr);
console.timeEnd("二叉树排序");//336ms
}
};
binaryTree.inOrderTravers(callback);
通过上边的例子可以看出,对99999个数据进行排序,二叉树(336ms),快速排序(720ms),冒泡排序(12617ms),但是当数据量很小的时候,基本看不出来之间的差距。说明数据结构和算法对大数据量的处理非常重要,对高并发的业务场景十分重要;
9.给定线段A(x1,y1),(x2,y2)和线段B(x3,y3),(x4,y4),请两条线的交点的坐标?
function hasSamePoint(a,b,c,d){
var denominator = (b.y - a.y)*(d.x - c.x) - (a.x - b.x)*(c.y - d.y);
if (denominator===0) { //如果两个线条平行,则肯定不存在交点
return false;
}
//线段所在直线的交点坐标(x,y)
var x = ( (b.x - a.x) * (d.x - c.x)*(c.y - a.y)
+ (b.y - a.y) * (d.x - c.x) * a.x
- (d.y - c.y) * (b.x - a.x) * c.x )/denominator;
var y = -( (b.y - a.y) * (d.y - c.y) * (c.x - a.x)
+ (b.x - a.x) * (d.y - c.y) * a.y
- (d.x - c.x) * (b.y - a.y) * c.y )/denominator;
// 判断交点是否在两条线段上
if ((x - a.x) * (x - b.x) <= 0 && (y - a.y) * (y - b.y)<= 0&& (x - c.x)*(x-d.x)<=0&&(y-c.y)*(y-d.y)<=0){
return{
x:x,
y:y
}
}
return false
}
console.log(hasSamePoint({x:1,y:2}, {x:11,y:24},{x:4,y:22},{x:31,y:25}));
10.必须要会使用的数据结构和算法有哪些?
数组,链表,队列,栈,堆,树,图。这几种非常常见;
排序和搜索算法。动态规划,贪心算法,背包问题。