数据结构和算法实例

综述:数据结构和算法是高级前端的必备知识,贵在总结,坚持积累

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结构?收集所有的标签,使用数组存储所有的标签?

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <!-- 避免IE使用兼容模式 -->
    <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
    <meta name="renderer" content="webkit">
    <title>基础信息</title>
    <!-- 浏览器标签图片 -->
    <link rel="icon" type="image/x-icon" href="/img/sf.png" media="screen" />
    <script src="//cdn.bootcss.com/redux/3.5.2/redux.min.js"></script>
</head>
<body>
<script>
      var tags = document.getElementsByTagName('*');
    var tagsArr = [];
    function countTag(){
        for (var i = 0; i < tags.length; i++) {
            tagsArr.push((tags[i].tagName).toLowerCase());
        }
        // 获取到页面的所有标签
        console.log(tagsArr);
        //定义一个数组用于存放相同的元素
        var temp = [];
        //定义一个空数组用于存放每一个标签;
        var tag =[];
        for (var i = 0; i < tagsArr.length; i++) {
            for (var j = i+1; j < tagsArr.length+1; j++) {
                if (tagsArr[i] == tagsArr[j]) {
                    temp.push(tagsArr[j]);
                    tagsArr.splice(j,1);
                    j--;
                }
                if (j == tagsArr.length -i) {
                    temp.push(tagsArr[i]);
                    tagsArr.splice(i,1);
                    i--;
                    tag.push(temp);
                    temp = [];
                }
            }
        }
        return tag;
    }
   console.log(countTag());

</script>
</body>
</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<n ; i++ ) {
          cache[i] = cache[i-2] + cache[i-1];
        }
      }
      console.log(cache);
      return cache[n-1];
    }
  }();
  console.log(IterMemoFib(20));
  console.timeEnd("数组缓存");

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;i<arr.length;i++){  //默认用的是第一个作为参考值,从下标为1的开始遍历
                if(arr[i]>middleValue){
                    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;i<arr.length;i++){
           for(var j=0;j<arr.length;j++){
               if(arr[i]>arr[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<node.key){
                 if(node.left===null){
                     node.left=newNode;
                 }else{
                     insertNode(node.left,newNode);
                 }
             }else{
                 if(node.right===null){
                     node.right=newNode;
                 }else{
                     insertNode(node.right,newNode);
                 }
             }
            // console.log(root); //这里的就是二叉树数据结构的存储值
         };
         this.insert=function(key){
             var newNode=new Node(key);
             if(root===null){
                 root=newNode;
             }else{
                 insertNode(root,newNode);
             }
         };
         //中序遍历实现代码
         var inOrderTraversNode=function(node,callback){
             if(node!==null){
                 inOrderTraversNode(node.left,callback);
                 callback(node.key);
                 inOrderTraversNode(node.right,callback);
             }
         }
         this.inOrderTravers=function(callback){
             inOrderTraversNode(root,callback);
         }
     }
    //构建一个二叉树数据结构
    var binaryTree=new BinaryTree();
    arr.forEach(function(key){
         binaryTree.insert(key);
    });
    var newArr=new Array();
    var callback=function(key){
        newArr.push(key);
        if(newArr.length>=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.必须要会使用的数据结构和算法有哪些?

数组,链表,队列,栈,堆,树,图。这几种非常常见;

排序和搜索算法。动态规划,贪心算法,背包问题。

11.多维数组的数据扁平化?

  • es6中的flat方法,专门用来解决这个问题
  •   JSON.stringify()先转成字符串,再replace掉[ ]这俩符号,然后再用JSON.parse()将其转成正常的数组即可

12.在一个数组中,存在不重复的元素,要求取出2个元素,使其之和为sum?求两个元素的下标?

function getTarget(arr,target){
    let result=[]
   for(let i=0;i<arr.length;i++){
       let index = arr.indexOf(target-arr[i])
         if(index>-1){
               result =[i,index];
          }
   }
    return result;
}
getTarget([1,2,3,4,6,8,9],7); // [4,0]

13.repeat方法,alert出n次hello word字符串?

function getTarget(n){
   for(let i=0;i<n;i++){
       console.log("hello world")
   }
}
getTarget(7);

14.对数组中1-100元素进行排序,如果这里的数字换成32位的整数,如何来处理呢?

对于正常的数组,直接使用sort()方法进行处理就行了。

在js中只能正常处理-2^31-2^31-1之间的数据,如果数据过大的话,需要将大数进行分段处理,首先需要将短的数据前方进行补0操作,使其长度保持一致。再进行分段处理切割比较。

15.两个大数之间的相加之和操作该如何处理?

16.求数组中出现频率最高的字符并统计其次数?

function findKey (obj,value, compare = (a, b) => a === b) {  
    return Object.keys(obj).find(k => compare(obj[k], value))
}
function maxSum(str){
    let obj = {};
    for(let i=0;i<str.length;i++){
        if(obj[str[i]]===undefined){
           obj[str[i]]=1
        }else{
            obj[str[i]]+=1
        }
       }
       //let maxNum = Math.max.apply(Array,(Object.values(obj)));
       //return [findKey(obj,maxNum),maxNum];

       let key='',value=0;
       for (let i in obj) {
       //如果当前项大于下一项
       if (obj[i]>value) {
        //就让当前值更改为出现最多次数的值
          key= obj[i];
          value = i;
       }
       return [key,value]
}
console.log(maxSum('asasaasd'));

17.找到字符串中的最大回文子字符串?

 

18.求一个数组中,和最大的连续子数组,并将这个数组和子数组和打印出来?

function maxSum(nums){
    let maxn = -Number.MAX_VALUE; start=0,end=0;
    let sum =0;
    nums.forEach(function(value,index,array){
      sum+=value;
      if(sum>maxn){
          maxn = sum;
      }  
      if(sum<0){
          sum=0;
          start = index+1;
      }
          end = index
    })
    return [maxn,start,end];
}
console.log(maxSum([1,2,-8,2,3,1])); //[6,3,5]

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值