「这是我参与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 地址。
解题思路:
- 首先得明白,ip地址的规则,一共4段,0独占一段,每一段取值范围在0-255
- 运用递归,遍历所有字符串能组成的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函数方法的调用,如果你觉得有帮助的话,就悄咪咪的点个赞吧!