CruxF / Blog

个人博客,记载学习的点点滴滴,怕什么技术无穷,进一寸有一寸的欢喜:sparkles:

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

前端工程师面试指南——算法篇

CruxF opened this issue · comments

判断一个单词是否是回文字符

概念: 回文是指把相同的词汇或句子,在下文中调换位置或颠倒过来,产生首尾回环的情趣,叫做回文,也叫回环。比如 mamam、redivider等。

很多人拿到这样的题目非常容易想到用for 将字符串颠倒字母顺序然后匹配就行了。其实重要的考察的就是对于reverse的实现。其实我们可以利用现成的函数,将字符串转换成数组,这个思路很重要,我们可以拥有更多的自由度去进行字符串的一些操作。

function checkPalindrom(str) {
  if(str == str.split('').reverse().join('')) {
    console.log("true")
  }
}
checkPalindrom("mamam")

去掉一组整型数组重复的值

这道问题出现在诸多的前端面试题中,主要考察个人对Object的使用,利用key来进行筛选。

function unique(arr) {
  let hashTable = {};
  let data = [];
  for (let i = 0, l = arr.length; i < l; i++) {
    if (!hashTable[arr[i]]) {
      hashTable[arr[i]] = true;
      data.push(arr[i]);
    }
  }
  console.log(data);
}
let arrs = [4, 5, 2, 4, 1];
unique(arrs);

统计一个字符串出现最多的字母

function findMaxDuplicateChar(str) {
  if (str.length <= 1) {
    return str;
  }
  let charObj = {};
  for (let i = 0; i < str.length; i++) {
    // charAt() 方法可返回指定位置的字符。
    // console.log(str.charAt(i))
    if (!charObj[str.charAt(i)]) {
      charObj[str.charAt(i)] = 1;
    } else {
      charObj[str.charAt(i)] += 1;
    }
  }
  // {r:1,e:1,q:1,a:3,d:1,f:1}
  // console.log(charObj)
  let maxChar = "";
  let maxValue = 1;
  for (var k in charObj) {
    if (charObj[k] >= maxValue) {
      maxChar = k;
      maxValue = charObj[k];
    }
  }
  console.log(maxChar);
}
findMaxDuplicateChar("reqaaadf");

排序算法

如果抽到算法题目的话,应该大多都是比较开放的题目,不限定算法的实现,但是一定要求掌握其中的几种,所以冒泡排序,这种较为基础并且便于理解记忆的算法一定需要熟记于心。冒泡排序算法就是依次比较大小,小的跟大的进行位置上的交换。

function bubbleSort(arr) {
  for (let i = 0, l = arr.length; i < l - 1; i++) {
    for (let j = i + 1; j < l; j++) {
      if (arr[i] > arr[j]) {
        let tem = arr[i];
        arr[i] = arr[j];
        arr[j] = tem;
      }
    }
  }
  console.log(arr);
}
let arrs = [3, 55, 12];
bubbleSort(arrs);


// 推理过程
当i=0
j ==> 1
arr[i] ==> 3
arr[j] ==> 55
也就是arr[0] = 0,arr[1] = 55

当i=1
j ==> 2
arr[i] ==> 55
arr[j] ==> 12
tem ==> arr[i]=55
arr[i] = arr[j] = 12
arr[j] = 55
也就是arr[1] = 12,arr[2] = 55

除了冒泡排序外,其实还有很多诸如 插入排序,快速排序,希尔排序等。每一种排序算法都有各自的特点。全部掌握也不需要,但是心底一定要熟悉几种算法。

比如快速排序,其效率很高,算法参考某个元素值,将小于它的值,放到左数组中,大于它的值的元素就放到右数组中,然后递归进行上一次左右数组的操作,返回合并的数组就是已经排好顺序的数组了。

function quickSort(arr) {
  //如果数组<=1,则直接返回
  if (arr.length <= 1) {
    return arr;
  }
  var pivotIndex = Math.floor(arr.length / 2);
  //找基准,并把基准从原数组删除
  var pivot = arr.splice(pivotIndex, 1)[0];
  //定义左右数组
  var left = [];
  var right = [];

  //比基准小的放在left,比基准大的放在right
  for (var i = 0; i < arr.length; i++) {
    if (arr[i] <= pivot) {
      left.push(arr[i]);
    } else {
      right.push(arr[i]);
    }
  }
  //递归
  return quickSort(left).concat([pivot], quickSort(right));
}
console.log(quickSort([4, 2, 6, 7, 1]));

下面是比较复杂难懂但是时间复杂度较低的代码,参考文章

// 原地交换函数,而非用临时数组
function swap(array, a, b) {
  [array[a], array[b]] = [array[b], array[a]];
}

// 划分操作函数
function partition(array, left, right) {
  // 用index取中间值而非splice
  const pivot = array[Math.floor((right + left) / 2)];
  let i = left;
  let j = right;
  while (i <= j) {
    while (compare(array[i], pivot) === -1) {
      i++;
    }
    while (compare(array[j], pivot) === 1) {
      j--;
    }
    if (i <= j) {
      swap(array, i, j);
      i++;
      j--;
    }
  }
  return i;
}

// 比较函数
function compare(a, b) {
  if (a === b) {
    return 0;
  }
  return a < b ? -1 : 1;
}

function quick(array, left, right) {
  let index;
  // 第一次:[3,2,1] 0 2
  // 第二次:[1,2,3] 0 1
  // console.log(array,left,right)
  if (array.length > 1) {
    index = partition(array, left, right);
    // 第一次:2
    // 第二次:1
    // console.log(index)
    if (left < index - 1) {
      quick(array, left, index - 1);
    }
    if (index < right) {
      quick(array, index, right);
    }
  }
  // return array;
  console.log(array);
}

function quickSort(array) {
  return quick(array, 0, array.length - 1);
};
let arrs = [3, 2, 1]
quickSort(arrs);

不借助临时变量,进行两个整数的交换

这种问题非常巧妙,需要大家跳出惯有的思维,利用 a , b进行置换。主要是利用 + – 去进行运算,类似 a = a + ( b – a) 实际上等同于最后 的 a = b;

function swap(a, b) {
  b = b - a;
  a = a + b;
  b = a - b;
  return [a, b];
}
console.log(swap(3, 8));

写一个斐波那契数列,长度限定为9

斐波那契数列,又称黄金分割数列,指的是这样一个数列:0、1、1、2、3、5、8、13、21、34、……在数学上,斐波纳契数列主要考察递归的调用。

function getFibonacci(n) {
  var fibarr = [];
  var i = 0;
  while (i < n) {
    if (i <= 1) {
      fibarr.push(i);
    } else {
      fibarr.push(fibarr[i - 1] + fibarr[i - 2])
    }
    i++;
  }
  return fibarr;
}
console.log(getFibonacci(9))

找出正数组的最大差值

这是通过一道题目去测试对于基本的数组的最大值的查找,很明显我们知道,最大差值肯定是一个数组中最大值与最小值的差。

function getMaxProfit(arr) {
  var minPrice = arr[0];
  var maxProfit = 0;
  for (var i = 0; i < arr.length; i++) {
    var currentPrice = arr[i];
    minPrice = Math.min(minPrice, currentPrice);
    var potentialProfit = currentPrice - minPrice;
    maxProfit = Math.max(maxProfit, potentialProfit);
  }
  return maxProfit;
}
// 出现bug
console.log(getMaxProfit([65, 6, 2]));
// 出现bug
console.log(getMaxProfit([65, 6]));
// 正常
console.log(getMaxProfit([65, 6, 99]));

下面是一个暂时没有bug的实现方式

function getMaxProfit(arr) {
  var max = arr[0];
  var min = arr[0];
  var res = 0;
  for (var i = 1; i < arr.length; i++) {
    if (arr[i] > max) {
      max = arr[i];
    }
    if (arr[i] < min) {
      min = arr[i]
    }
    res = max - min;
  }
  return res;
}
console.log(getMaxProfit([65, 6, 2]))
console.log(getMaxProfit([65, 6]))
console.log(getMaxProfit([65, 6, 99]))

随机生成指定长度的字符串

function randomString(n) {
  let str = 'abcdefghijklmnopqrstuvwxyz9876543210';
  let tmp = '';
  let i = 0;
  let l = str.length;
  for (i = 0; i < n; i++) {
    tmp += str.charAt(Math.floor(Math.random() * l));
  }
  return tmp;
}
console.log(randomString(5))

优质文章

1、面试官:阮一峰版的快速排序完全是错的
2、算法学习指南