前端算法与数据结构自学总结(实战篇)

《前端算法与数据结构自学总结(实战篇)》 2017年7月于长城

一、如下是一个tree树的实现,写出结果:

var s=[];
var arr=s;
    for(var i=0;i<3;i++){
    var pusher = {
        value: "item"+i
        },tmp;
     if(i!==2){
        tmp = []
        pusher.children = tmp
    }
    arr.push(pusher);
    arr = tmp;  // arr做了一个对象指针的移动,等于上一个children
}
console.log(s[0]);

// {
      value: "item0",
      children:[
           {
             value: "item1",
             children:[{
                 value: "item2"
             }]
            }
      ]
  }

二、查找如下有序数组中31出现的位置,最快的查找方法是什么,JavaScript怎么实现?

[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]

对于一个已经排好序的数组,最快定位的方法是二分查找

function find (arr, item) {
    var low = 0;  //设定下标
    var high = arr.length - 1; // 设定上标
    while (high >= low) {
        var mid = Math.floor((low + high) / 2);   //二分查找的关键
        if (arr[mid] === item) {
            return mid;
        }else if (arr[mid] > item) {
             high = mid;
        } else if (arr[mid] < item){
            low = mid;
        } 
    }
    return  -1;
}

三、 用JavaScript实现数组的快速排序:

快速排序过程只需要三步:

  • 1、在数据集中,选择一个元素作为“基准”(pivot)。(基准值可以任意选择,但是选择中间的值比较容易理解)
  • 2、所有小于”基准”的元素,都移到”基准”的左边;所有大于”基准”的元素,都移到”基准”的右边。
  • 3、对”基准”左边和右边的两个子集,不断重复第一步和第二步,直到所有子集只剩下一个元素为止。
    使用js数组方法及递归
function quickSort(arr) {
   if(arr.length <= 1) return arr;
   var index = Math.floor(arr.length / 2);
   var key = arr.splice(index, 1)[0];
   var left = [],right = [];
   arr.forEach(function(v){
       v <= key ? left.push(v) : right.push(v);
   });
   return quickSort(left).concat([key], quickSort(right));
}

四、写出单向链表和双向链表的添加和删除操作的实现过程。

单向链表的添加:

function insert(newElement, item){
    var newNode = new Node(newElement);  // 新建一个节点
    var current = this.find(item);   //找到item的位置(current在js中是引用,类似于C语言指针)
    newNode.next = current.next;  //将新节点的后继指向item的后继
    current.next = newNode;  // 修改item节点的后继指向新节点
}

单向链表的删除:

// 首先要找到删除元素的上一个节点
function findPrevious (item) {
    var currentNode = this.head;
    while (!(currentNode.next === null) && (currentNode.element !== item)) {
    return currentNode;
    }
}

function remove (item) {
    var prevNode = this.findPrevious(item);
    var currentNode = this.find(item); // 查找到当前要删除的节点
    if (!(prevNode.next === null)) {
        prevNode.next = prevNode.next.next; //待删除节点的前驱的后继 指向 原本待删除节点的后继
        currentNode.next = null; // 释放节点,防止内存泄漏
    }
}

双向列表的添加:

// 插入节点,注意插入的链指向
function insert(newElement, item){
    var newNode = new Node(newElement);  // 新建一个节点
    var current = this.find(item);   //找到item的位置
    newNode.next = current.next;  //将新节点的后继指向item的后继
        newNode.previous = current;
        current.next = newNode;
        if (newNode.next !== null) {
                newNode.next.previous = newNode; // 将item原本的位置的前驱指向新节点
        }
}

双向链表的删除:

function remove (item) {
    var currentNode = this.find(item);
    if (!(currentNode === null)) {
        currentNode.previous.next = currentNode.next; // 删除节点的前驱的后继,指向删除节点的后继
        currentNode.next.previous = currentNode.previous; //删除节点的后继的前驱,指向删除节点的前驱
        currentNode.next = null; // 释放节点,防止内存泄漏
        currentNode.previous = null;
    } else {
        currentNode.previous.next = null; // 尾节点的前驱的后继指向null
        currentNode.previous = null; // 释放尾节点
    }
}

五、用代码实现二叉搜索树,写出相关方法查找最小值。

//定义节点
function Node(data, left, right) {
    this.data = data;
    this.left = left;
    this.right = right;
}

// 插入值
function insert (data) {
    var n = new Node(data, null, null); // 定义一个新节点
    if(this.root === null) {
        this.root = n;
    } else {
        var current = this.root;
        var parent;
        while (true) {
            parent = current;
            if (data < current.data) {
                current = current.left; // 比当前值小就放左边
                if (current === null) {
                    parent.left = n;
                    break;
                }
            } else {    // 比当前值大就放右边
                current = current.right;
                if(current === null){
                    parent.right = n;
                    break;
                }
            }
        }
    }
}

// 找最小值
function getSmallest (root) {
    // 一直往左子树上去找,找到没有左节点即找到了最小值
    var current = this.root || root;
    while (!(current.left === null)) {
        current = current.left;
    }
    return current;
}

六、编写一个方法,求一个字符串的字节长度:

(一个英文字符占1个字节,一个中文字符占2个字节)

function getBytes(str) {
        var len = str.length;
        var bytes = len;
        for (var i = 0; i< len; i++) {
                if (str.charCodeAt(i) >= 128) {     // 如果判断是中文字符就+1
                        bytes++;
                }
        }
        return bytes;
}

七、找出一个正数数组的最大差值:

function getDifference(arr) {
        var minValue = arr[0];
        var maxDifference = 0;
        for (var i = 0; i < arr.length; i++) {
                var current = arr[i];
                minValue = Math.min(minValue, current);    // 用一个临时变量存较小的值
                var difference = current - minValue;
                maxDifference = Math.max(maxDifferent, potential);
        }
        return maxDifference;
}

ES6扩展运算符

function getDifference(arr){
    var max = Math.max(...arr);  // 找出最大值
    var min = Math.min(...arr);   // 找出最小值
    return max - min;
}

数组sort排序

function getDifference(arr){
    var arr = arr.sort();
        var min = arr[0];
        var max = arr[arr.length-1];
        return maxDifference = max - min;
}

八、判断一个单词是否是回文:

(如mamam)

function isPalindrome(str) {
    var len = str.length;
    var start = Math.ceil(len / 2);
    while (start < len) {
        if(str[start] !== str[len - start - 1]) {
            return false;
        };
        start++;
    }
    return true;
}

九、数组去重:

function unique(arr) {
    var result = [];

    arr.forEach(function(v){
        if(result.indexOf(v) < 0) {
            result.push(v);
        }
    });
    return result;
}

十、计算字符串中出现次数最多的字母及次数:

function findMaxDuplicate(str){
    if (str.length === 1) return str;
    
    var charObj = {};
    for(var i=0; i<str.length; i++){
        if(!charObj[str.charAt(i)]){
            charObj[str.charAt(i)] = 1;
        } else {
            charObj[str.charAt(i)] += 1;
        }
    }
    var maxChar = '',
    maxValue = 1;
    for(var k in charObj) {
        if (charObj[k] >= maxValue) {
            maxChar = k;    
            maxValue = charObj[k];
        }
    }
    return '出现次数最多的是:'+ maxChar +',一共'+charObj[maxChar]+'次'
}

十一、写一个isPrime()函数,当其为质数时返回为true,否则返回false。

(质数:大于1且只能被1和它本身整除的数)

function isPrime(number) {
    if (typeof number !== 'number' || !Number.isInteger(number)) {
        return false;
    } 
    if (number < 2) {
        return false;
    } else if (number === 2) {
        return true;
    } else if (number % 2 === 0) {
        return false;
    }
    var squareRoot = Math.sqrt(number); // 求平方根
    for(var i = 3; i <= squareRoot; i += 2) {
        if (number % i === 0) {
            return false;
        }
    }
    return true;
}

十二、对下列字符串进行排序,按照字符串中的数字排序:

“hell2o wor5ld Compa1y T4est 3abc”
1.首先对给定字符串根据空格进行分割,毕竟数组比字符串更容易操作。
2.接着制定排序规则,哪个单词中包含的数字更大,排名就靠后。
3.然后,用数组的sort方法,传入排序规则匿名函数,进行定制排序。
4.最后,将sort后的数组进行聚合,返回字符串。

function FindNumber(str){  
    for(var i=0;i<str.length;i++){  
        var chr = str.charAt(i);  
        if(!isNaN(chr)){  
            return parseInt(chr);  
        }  
    }  
}  
  
function Order(words){  
    return words.split(" ").sort(function(a,b){  
        return findNumber(a) - findNumber(b); 
    }).join(" ");  
}  

十三、写一个flat函数将如下一个多层嵌套数组输出成字符串。

输入:[‘a’, [‘b’, ‘c’], 1, 2, [‘d’, ‘e’], ‘f’, 3, 4]
输出:a, b, c, 1, 2, d, e, f, 3, 4

方法一:递归方法

var arr = ['a', ['b', 'c', ['d']], 1, 2, ['e', 'f'], 'g', 3, 4];
function flat (arr) {
      var result = [];
      var each = function (arr) {
            arr.forEach(item => {
                  if (item instanceof Array) {
                       each(item);
                   } else {
                       result.push(item);
                   }
            });
       }
       each(arr);
       return result.join(',');
}

flat(arr);

方法二:toString格式转换

var arr = ['a', ['b', 'c', ['d']], 1, 2, ['e', 'f'], 'g', 3, 4];

Array.prototype.toString = function () {
    return this.join(',');  // 这里this就是arr数组
}

var flat = function (arr) {
    return arr + '';
}

flat(arr);

十四、将1234567 变成 1,234,567,即千分位标注

function exchange(num) {
    num += ''; //转成字符串
    if (num.length <= 3) {
        return num;
    }

    num = num.replace(/\d{1,3}(?=(\d{3})+$)/g, (v) => {
        return v + ',';
    });
    return num;
}

exchange(1234567)  // 1,234,567

十五 、有100格台阶,可以跨1步可以跨2步,一共有多少种走法:

(本质是斐波那契数列)

function step(){
    this.n1 = 1;
    this.n2 = 2;
    this.total = 100;
    this.getFunction = getFunction;
}

var Stairs = new step();

function getFunction(){
    for(i=2; i<this.total;i++){
        res = this.n1 + this.n2;
        this.n1 = this.n2;
        this.n2 = res;
    }
    return res;
}

var totalStairs = Stairs.getFunction();
console.log(totalStairs);

// 方法二:
function fib(n) {
  let array = new Array(n + 1).fill(null)
  array[0] = 0
  array[1] = 1
  for (let i = 2; i <= n; i++) {
    array[i] = array[i - 1] + array[i - 2]
  }
  return array[n]
}

十六、多维数组问题
1、多维数组转一维数组:

let arr = ['a', ['b', 'c'], 1, 2, ['d', 'e'], 'f', 3, 4]
arr.concat.apply([], arr)  // ["a", "b", "c", 1, 2, "d", "e", "f", 3, 4]
    原文作者:JokerPeng
    原文地址: https://www.jianshu.com/p/d9b0634dd264
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞