算法题挑战(不是)

182 阅读3分钟

「这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战

前言

掘友好,我是cv竹叶,相信大家在前端面试过程中,笔试或者谈话的时候,总会遇到算法题!严格的需要你手写解题,松一点的可能问你想法思路,所以我在这里记录了一些古老的算法题,学一学里面的逻辑精髓!

算法题挑战(不是)

当然是学习其中的解题思路与方法啦,什么递归都通通用起来!

实现一个算法,字符串包含"[]" , "()" , "{}",判断是否正确闭合

解题思路:先定义一个对称符号的对象,再把字符串中的符号一一对应进去键值,再把键值相对应的符号向右值存到定义的数组,定义的数组值与原字符串符号向右的相比,有相同的就从定义的数组中删掉,剩下的就是不闭合的值了。

function isValid(str){
    let res = [];//暂存数组
    let arr = str.split('');//字符串转成数组
    let obj = {
        '{':'}',
        '[':']',
        '(':')',
    }
    if(arr.length % 2 !== 0) return false;//长度对2求余不等于0,肯定不对称
    for(let i=0;i<arr.length;i++){
         let index = arr[i];
         if(obj[index]){
             res.push(index);//把向左的符号,转成向右的,存起来
         }else if(index === obj[res.slice(-1)[0]]){
             res.pop();//从暂存数组尾部删掉,已存在的符号。
         }else{
             return false;
         }
    }
    return !res.length;//如果暂存数组没值,说明对称
}
isValid('[{}]');//true
isValid('{]');//false

复原IP地址

给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能从 s 获得的 有效 IP 地址 。你可以按 任何 顺序返回答案。

有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。

例如:"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址,但是 "0.011.255.245"、"192.168.1.312" 和 "192.168@1.1" 是 无效 IP 地址。

解题思路:

  1. 首先得明白,ip地址的规则,一共4段,0独占一段,每一段取值范围在0-255
  2. 运用递归,遍历所有字符串能组成的ip地址,存储起来。
示例:
输入:s = "101023"
输出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]

function ipFnc(s){
    let res = [];//存储结果的数组
    let arr = [];//暂存一种ip的数组
    function dfc(s,index,start){
        if(index===4){//ip有4段,达到就是一个完整的ip
            if(start===s.length){//遍历完全部字符串,存储结果
                res.push(arr.join('.'));//分割数组,存到结果数组
            }
            return;//跳出函数
        }
        if(start===s.length){//只有4个字符串,则直接输出ip
            return;
        }
        if(s.charAt(start)==='0'){//由于不能有前导零,如果当前数字为 0,那么这一段 IP 地址只能为 0
            arr[index]=0;
            dfc(s,index+1,start+1);
        }
        let addr = 0;//用于计算0-255的值
        for(let i=start;i<s.length;i++){
            addr = addr*10+parseInt(s.charAt(i));//计算每一段的ip数值
            if(addr>0&&addr<=255){//满足条件,存到数组里
                arr[index] = addr;
                dfc(s,index+1,i+1);
            }else{
                break;
            }
        }
    }
    dfc(s,0,0);
    return res;
}
ipFnc('0101023');//['0.10.10.23', '0.10.102.3', '0.101.0.23']

查找数组公共前缀

题目:

编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""。

示例 1:

输入:strs = ["flower","flow","flight"]
输出:"fl"

示例 2:

输入:strs = ["dog","racecar","car"]
输出:""
解释:输入不存在公共前缀。

解题思路:主要是对数组的每一个值的字符串,展开来一个一个字符进行判断,运用startsWith()函数,对字符串的首字母进行判断,如果没有共同字符串,则返回正确结果。

答案:

function strFn(arr){
    let frist = arr[0];
    let index = 0;
    if(arr instanceof Array){//判断是否是数组
        while(index<arr.length){//循环字符
            let str = frist.slice(0,index+1);//取出第一个数组的字符
            for(let i=0;i<arr.length;i++){//把截取的字段,和原本数组中的值进行循环比较
                if(!arr[i] || !arr[i].startsWith(str)){//startsWith首字符串
                    return frist.slice(0,index);//返回公共前缀字符串
                }
            }
            index++;
        }
        return frist;
    }else{
        return false;
    }
}
strFn(["flower","flow","flight"]);//fl

字符串最长的不重复子串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

题目:
示例 1:

输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

示例 2:

输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

解题思路:运用了字符串截取方式slice()函数,对不重复的字符串进行截取存储,用indexOf()判断重复的字符,如果存在则在重复的字符处,为开始进行新的字符串截取,直到遍历完字符串,得到最长不重复的字符。

答案:

function maxStr(str){
    let max = 0;//最大字符串长度
    let left = 0;//左坐标
    let right = 1;//右坐标
    if(str.length===0){
        return 0;
    }
    while(right <= str.length){
        let lr = str.slice(left,right);//截取字符串
        const index = lr.indexOf(str[right]);//取一个字符与lr字符串里查是否重复字符
        if(index > -1){//存在重复字符
            left = index + left + 1;
        }else{
            lr = str.slice(left,right + 1);//切割出不重复的字符串
            max = Math.max(max,lr.length);//存最大不重复字符串长度
        }
        right++;
    }
    return max;
}
maxStr('abcabcbb');//3

如何找到数组中第一个没出现的最小正整数? 怎么优化

题目:

给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。

示例 1:

输入:nums = [1,2,0]
输出:3

示例 2:

输入:nums = [3,4,-1,1]
输出:2

解题思路:按照1,2,3...的顺序来排的话,我们只需要遍历,把不该出现在顺序位子的下标进行返回就可以了。

答案:

function firstMax(nums){
    //对数组排成理想的顺序数字
    for(let i=0;i<nums.length;i++){
        while(nums[i]>=1&&//判断从1开始
            nums[i]<=nums.length&&//字符串最大长度结束
            nums[i] !== nums[nums[i]-1]//1-n的数字顺序排序,不在顺序位子的就进行换位子处理
        ){
            const temp = nums[nums[i]-1];
            nums[nums[i]-1] = nums[i];
            nums[i] = temp;
        }
    }
    //理想顺序数字[1,2,3,4,5...],
    for(let i=0;i<nums.length;i++){
        if(nums[i] !== i+1){
            return i+1;//返回顺序数字中,不在对的位置的数字下标
        }
    }
    return nums.length + 1;//进来就是顺序数字了,则直接返回
}
firstMax([1,4,6,5,2,7]);//3

算法:二叉树

题目:

有这么一个数据结构:

const data = [
  {
    "id": "1",
    "sub": [
      {
        "id": "2",
        "sub": [
          {
            "id": "3",
            "sub": null
          },
          {
            "id": "4",
            "sub": [
              {
                "id": "6",
                "sub": null
              }
            ]
          },
          {
            "id": "5",
            "sub": null
          }
        ]
      }
    ]
  },
  {
    "id": "7",
    "sub": [
      {
        "id": "8",
        "sub": [
          {
            "id": "9",
            "sub": null
          }
        ]
      }
    ]
  },
  {
    "id": "10",
    "sub": null
  }
]
现在给定一个id,要求实现一个函数

findPath(data, id) {

}
返回给定id在 data 里的路径
示例:

id = "1" => ["1"]
id = "9" => ["7", "8", "9"]
id = "100"=> []
PS: id 全局唯一,无序

解题思路:根据传入的目标id,对数组的值进行遍历与递归,先把父级的id全部存储到数组来,往子级走下去,到根部还是没有找到目标id,则从父级存储的数组中删除当前子级的id,如果找到目标id了,则可以直接返回id数组了。

解答:

function findPath(data,id){
    let path = [];
    try{
        function getPath(item){
            path.push(item.id);
            if(item.id===id){
                throw('取到值了')
            }
            if(item.sub && item.sub.length>0){
                for(let i=0;i<item.sub.length;i++){
                    getPath(item.sub[i]);//递归
                }
                path.pop();//不是目标id,删除数组中的值
            }else{
                path.pop();//没子集,不是目标id,删除数组中的值
            }
        }
        for(let i=0;i<data.length;i++){
            getPath(data[i]);//循环每一个对象
        }
    }catch(e){
        return path;
    }
}
findPath(data,'9');//['7', '8', '9']

结言

我们要学习里面的解题思路,就算不会写,也可以在编写的过程中,学到很多js函数方法的调用,如果你觉得有帮助的话,就悄咪咪的点个赞吧!