常见的JavaScript面试算法

390 阅读4分钟

斐波那契数列

// Base
function Fibonacci1(n) {
    if (n === 1) {
        return 1
    }
    if (n === 2) {
        return 1
    }
    if (n > 2) {
        return Fibonacci1(n - 1) + Fibonacci1(n - 2)
    }
}

// More
function Fibonacci2(n) {
    if (n === 1 || n === 2) {
        return 1
    } else {
        var pre = 1
        var next = 1
        var target
        for (var i = 3; i <= n; i++) {
            target = pre + next
            pre = next
            next = target
        }
        return target
    }
}

var start = new Date().getTime()
console.log(Fibonacci1(30))       // 832040
var end = new Date().getTime()
console.log(end - start)         // 43

start = new Date().getTime()
console.log(Fibonacci2(30))      // 832040
end = new Date().getTime()
console.log(end - start)         // 0
  • 上述写了实现斐波那契数列的两种方法,第一种方法用了递归;第二种方法用了循环赋值;通过上述实践,可以看出第二种方式的时间空间复杂度很小很小。所以,在此推荐用第二种方法实现斐波那契数列

字符串反转

var strChar = 'wangsuoling'

// Base
function strReserve1 (str) {
  if (typeof str !== 'string') {
    return false
  } else {
    var result = ''
    // 字符串通过索引取值,IE7及其以前的版本不支持
    for (var i = str.length - 1; i >= 0 ; i--) {
      result += str[i]
    }
    return result
  }
}

// More
function strReserve2 (str) {
  if (typeof str !== 'string') {
      return false
  } else {
      let strNew = str.split('').reverse().join('')
      return strNew
  }
}

var start = new Date().getTime()
console.log(strReserve1(strChar))       // 'gnilousgnaw'
var end = new Date().getTime()
console.log(end - start)         // 31

start = new Date().getTime()
console.log(strReserve2(strChar))      // 'gnilousgnaw'
end = new Date().getTime()
console.log(end - start)         // 0
  • 上述写了实现字符串反转的两种方法,通过上述实践,可以看出第二种方式的时间空间复杂度很小很小。所以,在此推荐用第二种方法实现字符串反转

判断字符串是否是回文

var str1 = 'abeffeba'
var str2 = 'abcdcba'
var str3 = 'abcd1234'

// Base
function huiWen1 (str) {
    for (let i = 0; i < str.length; i++) {
        if (str[i] === str[str.length - 1 - i]) {
            return true
        } else {
            return false
        }
    }
}

// Middle--利用栈 后进先出的特性
function huiWen2 (str) {
    var stackNewArr = [], len, mid, next, top
    len = str.length
    mid = Math.floor(len / 2 - 1)
    top = 0
    for (var i = 0; i <= mid; i++) {
        stackNewArr[++top] = str[i]
    }
    if (len % 2 === 0) {
        next = mid + 1
    } else {
        next = mid + 2
    }
    for (var j = next; j <= len-1; j++) {
        if (str[j] !== stackNewArr[top]) {
        break
        }
        top--
    }

    if (top === 0) {
        return true
    } else {
        return false
    }
}

// More
function huiWen3 (str) {
    let strNew = str.split('').reverse().join('')
    if (strNew === str) {
        return true
    } else {
        return false
    }
}

var start = new Date().getTime()
console.log(huiWen1(str2))       // true
var end = new Date().getTime()
console.log(end - start)         // 31

start = new Date().getTime()
console.log(huiWen2(str2))      // true
end = new Date().getTime()
console.log(end - start)         // 0

start = new Date().getTime()
console.log(huiWen3(str2))      // 'gnilousgnaw'
end = new Date().getTime()
console.log(end - start)         // 0
  • 上述写了实现判断字符串是否是回文的三种方法,通过上述实践,可以看出第二种方式 和 第三种方式 的时间空间复杂度很小很小。所以,在此推荐用第二种方法 或者 第三种方法实现字符串反转

数组去重

// 思路:设置一个临时数组temp,然后遍历要去重的数组arr,如果arr中的元素能够在temp中找到,则跳过此元素,否则将此元素存入temp,最后返回temp
// Base
function unique(arr){
    var temp = [];
    var len = arr.length;
    for(var i = 0; i < len; i++){
        if(temp.indexOf(arr[i]) === -1) temp.push(arr[i]);
    }    
    return temp;
}

// More
function unique( arr ) {
    var temp = [];
    var len = arr.length;
    for (var i = 0; i < len; i++) {
        var isRepeated = false;
        for ( var j = 0; j < temp.length; j++){
                if ( arr[i] === temp[j] ){                    
                       isRepeated = true;
                       break;
                   }
        }
        if ( !isRepeated ) temp.push( arr[i] );
    }
    return temp;
}

// 思路:设置一个临时数组temp,然后遍历要去重的数组arr,如果arr[i]中的元素在arr中出现的第一次的位置也为i,则将其存入temp,否则跳过此元素,最后返回temp
// Base
function unique(arr){
    var temp = [];
    var len = arr.length;
    for (var i = 0; i <len; i++){
        if(arr.indexOf([arr[i]) === i) temp.push(arr[i]);
    }
    return temp;
}

// 思路:设置一个临时对象tempObj,然后遍历要去重的数组arr, 如果arr[i]中的元素在此对象中有标记,则跳过,否则在临时对象中进行标记,并将其存入临时数组tempArr, 最后返回tempArr
// Base
function unique(arr){
    var tempObj = {};
    var tempArr = [];
    var len = arr.length;
    for (var i = 0; i < len; i++) {
        if ( !tempObj[arr[i]] ){
            tempObj[arr[i]] = true;
            tempArr.push(arr[i]);
        }
    }
    return tempArr;
}

// 思路:对要去重的数组 arr 先进行排序,这样重复的元素就排在了相邻的位置,然后对数组 arr 进行遍历,将arr[i] 与 临时数组 temp 中的最后一个元素进行比较,如果不同则将其存入临时数组,如果相同则跳过此元素,最后返回临时数组。
// Base
function unique( arr ) {
    var temp = [];
    var len = arr.length;
    arr.sort();
    temp.push(arr[0]);
    for ( var i = 1; i < len; i++ ) {
        if ( arr[i] !== temp[temp.length-1] ) temp.push(arr[i]);
    }
    return temp;
}

二分查找

var find = function (arr, ele) {
    var start = 0;
    var end = arr.length - 1;

    while (end - start > 1){
        var mid =  parseInt((end + start) / 2);
        if(arr[mid] == ele){
            return true;
        } else if (arr[mid] > ele){
            end = mid - 1;
        } else {
            start = mid + 1;
        }
    }
    if(end - start == 1){
        if((arr[end] == ele) || (arr[start] == ele)){
            return true;
        }
    }
    return false;
}

var arr = [1, 3, 5, 6, 7, 9, 11]
var ele = 3

console.log(find(arr, ele))