面试之常见算法题

344 阅读3分钟

面试题中常常会有手写算法题, 现在总结了几个, 并会持续更新中, 有疑问多多提出

1. 数组全排列

  • 数组[1,2,3,4] 得到数组的全排列[1,2,4,3] [2,1,4,3] ...
  • 思路: 回溯 + 递归
    function totalArr(arr) {
      const result = []; // 返回的最终结果
      const obj = {}; // 用来判断是否有使用过某个数
      // 深度优先遍历
      function dfs(arrItem) {
        // 两个数组长度相同, 结果推进arr中
        if (arrItem.length === arr.length) {
          result.push([...arrItem]);
          return;
        }
        for (const num of arr) {
          // for of循环
          // 遍历数组
          if (obj[num]) continue; // 跳过本次循环
          arrItem.push(num);
          obj[num] = true;
          dfs(arrItem); // 递归找
          arrItem.pop(); // 回溯
          obj[num] = false;
        }
      }
      dfs([]);
      return result;
    }
    const arr = totalArr([1, 2, 3]);

2.最长不重复字串

  • 思路: 滑动窗口 如果出现重复字符 清空数组 重新计算数组长度
    function maxCountNotReapeat(s) {
      let max = 0;
      let arr = [];
      for (let i = 0; i < s.length; i++) {
        // arr.push(s);
        let index = arr.indexOf(s[i]); // 每个元素的索引
        if (index !== -1) {
          arr.splice(0, index+1); // 截取从0到index+1的所有字符
          
        }
        arr.push(s[i]); // 重新往arr里面添加值
        max = Math.max(arr.length, max); // 更新max的值
      }
      return max;
    }
    // console.log(maxCountNotReapeat("abbbcdsfgs"));

3. 数组中第K大的数

  • sort后拿对应的索引
    function kNum(arr, k) {
      return arr.sort((a, b) => b - a)[k - 1];
    }
    // 如果需要不重复, 可以使用new Set() 去重
    console.log(kNum([1, 2, 3, 4, 5, 4, 3, 2, 3], 3));

4. 回文字符串

题目: 输入:  'a man, nam,a'
      输出: true
  • 双指针
  • l指向头部, r指向尾部
  • 两头的指针向中间靠拢, 以相遇为结束条件, 若指向的字符不同, 则不是回文字符串
  • 另本题忽略大小写及其他字符, 遇到这些字符, 需要跳出本次循环
    function isPalindrome(s) {
      let l = 0;
      let r = s.length - 1;
      let flag = true;
      while (l < r) {
        // 验证字符是否是字母或数字, 如果不是跳过本次循环
        if (!/[^A-Za-z0-9]/.test(s[l])) {
          l++;
          continue; // 跳出本次迭代
        }
        if (!/[^A-Za-z0-9]/.test(s[r])) {
          r--;
          continue;
        }
        if (l < r && s[l].toLowerCase() !== s[r].toLowerCase()) {
          flag = false;
          break; // 跳出循环
        }
        l++;
        r--;
      }
      return flag;
    }

    isPalindrome("232, a232");
    isPalindrome("232,    a232");
    isPalindrome("abcba");
    isPalindrome("ab");

5.js大数相加

JavaScript能精确表示的数字是有限的,JavaScript可以精确到个位的最大整数是9007199254740992,也就是2的53次方,超过这个范围就会精度丢失,造成JavaScript无法判断大小

  • 解法: 转成字符串相加
  • 例:1255 + 456
初始化  进位 t = 0

0:  x + y + t      /10  商(t)  余(p)
1:  5 + 6 + 0 = 11 /10   1      1   
2:  5 + 5 + 1 = 11 /10   1      1   
3:  2 + 4 + 1 = 7  /10   0      7   
4:  1 + 0 + 0 = 1  /10   0      1   
结果:1711

// 48 是字符 0 的ASCII码

/**
 * @param {string} num1
 * @param {string} num2
 * @return {string}
 */
var addStrings = function (num1, num2) {
    let res = ''
    let i = num1.length - 1, j = num2.length - 1, flag = 0
    while (i >= 0 || j >= 0 || flag !== 0) {
        if (i >= 0) flag += num1.charCodeAt(i--) - 48
        if (j >= 0) flag += num2.charCodeAt(j--) - 48
        res = '' + flag % 10 + res
        flag /= 10
        // 向下取整
        flag = ~~flag
    }
    return res
};

6. 链表中倒数第k个节点

给定一个链表: 1->2->3->4->5, 和 k = 2.

返回链表 4->5.

// 1. 快慢指针
// 快指针先走k,慢指针再走,快指针到头,慢指针正好倒数k,此时返回慢指针即为所求。
var getKthFromEnd = function(head, k) {
    let fast = head;
    let slow = head;
    let flag = 0;
    while (fast) {
        if (flag >= k) {
            slow = slow.next;
        }
        fast = fast.next;
        flag ++;
    }
    return slow;
};


// 2. 数组
// 由于链表的长度无法直接获取,因此必须遍历链表。
// 利用数组中找到倒数第k个元素十分方便的特性,可以把链表转化为数组后直接输出目标链表节点。
var getKthFromEnd = function(head, k) {
    let p = head
    const map = []
    while(p.next!==null){
        map.push(p)
       p = p.next
    }
    map.push(p)
    return map[map.length-k]
};

数组转成树形结构

var source = [
    {
      id: 1,
      pid: 0,
      name: 'body',
    },
    {
      id: 5555,
      pid: 0,
      name: 'script',
    },
    {
      id: 55551,
      pid: 5555,
      name: 'js',
    },
    {
      id: 2,
      pid: 1,
      name: 'title',
    },
    {
      id: 3,
      pid: 1,
      name: 'div',
    },
    {
      id: 4,
      pid: 3,
      name: 'span',
    },
    {
      id: 5,
      pid: 3,
      name: 'icon',
    },
    {
      id: 6,
      pid: 4,
      name: 'subspan',
    },
  ];

  function toTree(data) {
    let result = [];
    if (!Array.isArray(data)) {
      return result;
    }
    let map = {};
    data.forEach(item =>{
      map[item.id] = item
    })

    data.forEach(item =>{
      let parent = map[item.pid]
      if(parent){
        parent.children = parent.children || []
        parent.children.push(item)
      }else{
        result.push(item)
      }
    })
    return result
}


let res = toTree(source)
// console.log(res, 'res');