前端常见代码题

ACM模式的输入输出代码

var lengthOfLongestSubstring = function(s) {
    if(s.length == 0) return 0
    let dp = new Array(s.length)
    dp[0] = 1;
    let map = new Map();
    map.set(s[0],0)
    for(let i=1; i<s.length; i++){
    if(!map.has(s[i])) map.set(s[i],-1)
    if(dp[i-1] < i - map.get(s[i])){
        dp[i] = dp[i-1] + 1
    }else{
        dp[i] = i - map.get(s[i])
    }
    map.set(s[i],i)
    }
    return Math.max(...dp)
};
//ACM输入输出代码
var readline = require('readline')
const r1 = readline.createInterface({
	input:process.stdin,
	input:process.stdout
})
r1.on('line',function(line){
	let result = lengthOfLongestSubString(line)
	console.log(result)
})
r1.on('close',function(){
	process.exit()
})

1.判断括号的合法性

function isValid(str){
    let left = [];
    // 将右括号转换为左括号
    let rightToLeft = (c) =>{
        if(c==")") return "("
        else if(c=="]") return "["
        else return "{"
    }
    for(let i=0; i<str.length; i++){
        if(str[i]=="(" || str[i]=="[" || str[i]=="{"){
            //左括号直接如栈
            left.push(str[i])
        } else {
            //字符是右括号
            //js中好像没有查看栈顶的方法
            if(left.length!==0 && rightToLeft(str[i])==left[left.length-1]){
                left.pop()
            }else{
                return false
            }
        }
    }
    return left.length == 0
}
let str = "[]{}()}"
console.log(isValid(str))

2.最长递增子序列(Longest Increasing Subsequence,简写LIS)

1)使用动态规划的方法,时间复杂度为 O ( n 2 ) O(n^2) O(n2)

function lengthOfLIS(arr){
    let dp = new Array(arr.length).fill(1)
    for(let i=0; i<arr.length; i++){
        for(let j=0; j<i; j++){
            if(arr[i]>arr[j]){
                dp[i] = Math.max(dp[i],dp[j]+1)
            }
        }
    }
    return Math.max(...dp)
}
let array = [1,2,3,4,2,5,8,2,7,1]
console.log(lengthOfLIS(array))

2)使用动态规划+二分搜索

function lengthOfLIS(arr){
    //一个牌堆数组
    let top = new Array(arr.length)
    let piles = 0;
    for(let i=0; i<arr.length; i++){
        let poker = arr[i]

        //搜索左侧边界的二分搜索
        let left = 0, right = piles;
        while(left < right){
            let mid = (right+left)>>1
            if(top[mid] > poker){
                right = mid;
            }else if(top[mid]<poker){
                left = mid + 1
            }else{
                right = mid
            }
        }

        //如果没有找到合适的牌堆,新建一堆
        if(left == piles) piles++;
        //把这张牌放到牌的堆顶
        top[left] = poker
    }
    console.log(top)
    return piles
}
let array = [6,3,5,10,11,2,9,1,13,7,4,8,12]
console.log(lengthOfLIS(array))

3.最长不含重复字符串的子字符串(剑指offer 48)

var lengthOfLongestSubstring = function(s) {
    if(s.length == 0) return 0
    let dp = new Array(s.length)
    dp[0] = 1;
    let map = new Map();
    map.set(s[0],0)
    for(let i=1; i<s.length; i++){
    if(!map.has(s[i])) map.set(s[i],-1)
    if(dp[i-1] < i - map.get(s[i])){
        dp[i] = dp[i-1] + 1
    }else{
        dp[i] = i - map.get(s[i])
    }
    map.set(s[i],i)
    }
    return Math.max(...dp)
};

4.两数之和(力扣第1题)

1)暴力解法 O ( n 2 ) O(n^2) O(n2)

var twoSum = function(nums, target) {
    let res = [];
    for(let i=0; i<nums.length; i++){
        for(let j=i+1; j<nums.length; j++){
            if(nums[i] + nums[j] == target){
                res.push(i)
                res.push(j)
                return res
            }
        }
    }
};

2)利用哈希表将时间复杂度降低为 O ( n ) O(n) O(n),此方法应该最优!

var twoSum = function(nums, target) {
    const map = new Map();
    for(let i=0; i<nums.length; i++){
        if(map.has(target-nums[i])){
            return [map.get(target-nums[i]),i]
        }
        map.set(nums[i],i)
    }
};

3)双指针(自己写的,有点粗糙)

var twoSum = function(nums, target) {
    //此处相当于深拷贝了
    let arr = nums.slice(0);
    //递增序列
    arr.sort((a,b) => a-b)
    let head = 0, tail = arr.length-1;
    let res = [];
    while(head < tail){
        if(arr[head] + arr[tail] < target){
            head++
        }else if(arr[head] + arr[tail] > target){
            tail--
        }else{
            res.push(nums.indexOf(arr[head]))
            res.push(nums.lastIndexOf(arr[tail]))
            return res
        }
    }
};

5.和为s的两个数字(剑指 Offer 57)

使用双指针求解

这一题和上一题相比,输入的序列是一个递增的序列!所以比较简单!

var twoSum = function(nums, target) {
    let i = 0, j = nums.length - 1;
    let res = [];
    while(true){
        if(nums[i]+nums[j]>target){
            j--;
        }else if(nums[i]+nums[j]<target){
            i++;
        }else{
            res.push(nums[i])
            res.push(nums[j])
            return res;
        }
    }
};

6.三数之和

使用 排序+双指针+去重+break+continue+return求解

break 是立即结束语句,并跳出语句,进行下个语句执行。它是用来退出循环或者switch语句,所以只有当它出现在这些语句时,这种形式的break语句才合法。

for(let i=1; i<=10; i++){
	//当i=6的时候,直接退出for这个循环。
	//这个循环将不再被执行,直接进入下一个语句
	if(i==6){
		break;
	}
    console.log(i)  // 12345
}

continue 结束本次循环,循环变量继续递增或递减,开始下次循环。continue语句只能用于while,do/while,for,或者for/in语句的循环体内,在其它地方使用都会引起错误。

for(let i=1; i<=10; i++){
	//当i=6的时候,跳过本次循环个循环。
	if(i==6){
		break;
	}
    console.log(i)  //12345678910
}

return 停止函数。return 语句就是用于指定函数返回的值。return语句应用返回只能出现在函数体内,出现在代码的其它任何地方都会造成语法错误。

function format(data){
	if(data<10){
		return "0" + data;
	}else{
		return data;
	}
}
var threeSum = function(nums) {
    if(nums.length<3) return []
    let res = [];
    nums.sort((a,b) => a -b)
    for(let i=0; i<nums.length; i++){
        //不是固定中间的数,而是固定了最左边的数
        if(nums[i] > 0) break;
        if(i>0 && nums[i] == nums[i-1]) continue //去重
        let left = i+1, right = nums.length-1;
        while(left < right){
            if(nums[i] + nums[left] + nums[right] == 0){
                res.push([nums[i],nums[left],nums[right]])
                while(left<right && nums[left] == nums[left+1]) left++;
                while(left<right && nums[right] == nums[right-1]) right--;
                left++;
                right--;
            }else if(nums[i] + nums[left] + nums[right] < 0){
                left++
            }else{
                right--
            }
        }
    }
    return res;
};

7.第一次只出现一次的字符(力扣第50题)

var firstUniqChar = function(s) {
	//用对象的方法写
    obj = {};
    for(let i=0; i<s.length; i++){
        if(obj[s[i]]){
            obj[s[i]]++;
        }else{
            //在对象中创建新属性
            obj[s[i]] = 1;
        }
    }
    for(let i in obj){
        if(obj[i] == 1){
            return i;
        }
    }
    return ' ';
};
var firstUniqChar = function(s) {
    let map = new Map();
    for(let i=0; i<s.length; i++){
        if(map.has(s[i])){
            map.set(s[i],map.get(s[i])+1)
        }else{
            map.set(s[i],1)
        }
    }
    for(let item of map){
        if(item[1] == 1){
            return item[0]
        }
    }
    return ' '
};

8.排序

1)冒泡排序

function bubbleSort(arr){
    for(let i=0; i<arr.length; i++){   //第一层控制趟数
        for(let j=0; j<arr.length-1-i; j++){ //第二层控制是否交换
            if(arr[j] > arr[j+1]){
                [arr[j],arr[j+1]] = [arr[j+1],arr[j]]
            }
        }
    }
    return arr
}
let arr = [1,2,8,3,7,5]
console.log(bubbleSort(arr))

2)快速排序

function quickSort(arr){
    if(arr.length<=1) return arr
    let left = [], right = [];
    let index = arr.length>>1
    //从数组的index索引位置开始,删除一个数
    //返回含有被删除元素的数组,并且取到该值
    let p = arr.splice(index,1)[0]
    for(let i=0; i<arr.length; i++){
        if(arr[i] <= p){
            left.push(arr[i])
        }else{
            right.push(arr[i])
        }
    }
    return quickSort(left).concat(p,quickSort(right))
}
let arr = [1,2,8,3,7,5]
console.log(quickSort(arr))

9.数组扁平化的方法

1.使用递归的方法,实现数组的扁平化

const flatten = (arr) => {
    let res = [];
    for(let i = 0; i < arr.length; i++){
        //如果arr的第i项是数组的话,就做递归
        //如果不是数组的话,就直接push进去
        if(Array.isArray(arr[i])){
            res = res.concat(flatten(arr[i]))
        }else{
            res.push(arr[i])
        }
    }
    return res
}
let arr = [1,[2,[3,4]]]
console.log(flatten(arr))

2.采用扩展运算符和some方法,两者共同使用达到数组扁平化的目的:

const flatten = (arr) => {
    //1.箭头函数如果不使用大括号,那么箭头后面只能有一行代码,
    //而且省略大括号会隐式的返回这行代码
    //2.some()方法,如果有一项函数返回true,
    //则这个方法返回true,否则返回false
    while(arr.some((item) => Array.isArray(item))){
        //3.concat()方法用于连接两个或者多个数组
        //arr.concat(arr1, arr2, ..., arrX)
        //其中,concat()的参数可以是具体的值也可以是数组
        //重点!!!如果要进行concat()操作的参数是数组,
        //那么添加的是数组的元素,而不是数组,但是只能解决一层的数组问题
        //4.扩展运算符...arr解构数组
        console.log(arr)
        arr = [].concat(...arr)
    }
    return arr;
}
let arr = [1,[2,[3,4]]]
console.log(flatten(arr))

10.字符串中出现次数最多的字符

function maxCountStr(str){
    const map = new Map();
    let maxCount = 0;
    let res = [];
    for(let i=0; i<str.length; i++){
        if(map.has(str[i])){
            maxCount = Math.max(maxCount,map.get(str[i])+1)
            map.set(str[i],map.get(str[i]) + 1)
        }else{
            map.set(str[i],1)
        }
    }
    for(let item of map){
        if(item[1] == maxCount){
            res.push(item[0])
        }
    }
    return res;
}
const string = 'goodstudydaydayup'
console.log(maxCountStr(string)) //['d']

11.判断两个任意类型的变量是否相等

//判断两个任意类型的变量是否相等
//a和b是任意类型的数据。当a和b的值和类型都相等的时候,返回‘true'.
//1.console.log(equals(1,1)); //true
//2.console.log(equals(1,'1')) //false
//3.console.log(equals([1,2,3],[1,2,3])) //true
//4.console.log(equals([1,2,3],[3,2,1])) //false
//5.console.log(equals([1,2,3],'[1,2,3]')) //false
//6.var person = {'name':'Terry', age:22};
//  var another = JSON.parse(JSON.stringify(person));
//  console.log(equlals(person,another)); //true
const equals = (a,b) => {
    //判断类型
    const typeA = getObjType(a)
    const typeB = getObjType(b)
    if(typeA !== typeB){
        return false
    }else if(typeA == 'Base'){
        return a === b
    }else if(typeA === 'Array'){
        if(a.length !== b.length){
            return false
        }else{
            for(let i=0; i<a.length; i++){
                if(!equals(a[i],b[i])){
                    return false
                }
            }
            return true
        }
    }else if(typeA === 'Object'){
        if(Object.keys(a).length !== Object.keys(b).length){
            return false
        }
        for(var key in a){
            if(!equals(a[key],b[key])){
                return false
            }
        }
        return true
    }
}

const getObjType = (obj) => {
    const type = Object.prototype.toString.call(obj)
    switch(type){
        case '[object Array]':
            return 'Array'
            break
        case '[object Object]':
            return 'Object'
            break
        case '[object Function]':
            return 'Function'
            break
        case '[object Undefined]':
            return 'Base'
            break
        case '[object Null':
            return 'Base'
            break
        case '[object Number]':
            return 'Base'
            break
        case '[object String]':
            return 'Base'
            break
        case '[object Boolean]':
            return 'Base'
            break
    }
}
// console.log(equals(1,1)); //true
// console.log(equals(1,'1')) //false
// console.log(equals([1,2,3],[1,2,3])) //true
// console.log(equals([1,2,3],[3,2,1])) //false
// console.log(equals([1,2,3],'[1,2,3]')) //false
var person = {'name':'Terry', age:22};
var another = JSON.parse(JSON.stringify(person));
console.log(equals(person,another)); //true

12.数组去重(包括有NaN和复杂数据类型)

13.超长整数相加

//超大整数相等
function add(a,b){
    var arrA = a.split('').reverse().map(item => parseInt(item))
    var arrB = b.split('').reverse().map(item => parseInt(item))
    var maxLen = arrA.length > arrB.length ? arrA.length : arrB.length
    for(let i=0; i<maxLen; i++){
        arrA[i] = arrA[i] !== undefined ? arrA[i] : 0
        arrB[i] = arrB[i] !== undefined ? arrB[i] : 0
    }
    const resultArr = new Array(maxLen + 1).fill(0) 
    // 注意这里是i小于maxLen
    for(let i=0; i<maxLen; i++){
        let temp = arrA[i] + arrB[i] + resultArr[i]
        if(temp>10){
            temp -= 10
            resultArr[i+1] = 1
        }
        resultArr[i] = temp
    }
    resultArr[maxLen] == 0 ? resultArr.pop() : resultArr
    console.log(resultArr)
    return resultArr.reverse().join('')
}

const num1 = '123456789101112131415161718191132545464353'
const num2 = '912343435354353534634554352345436234652'
console.log(add(num1,num2))

14.防抖

<!DOCTYPE html>
<html lang="en">
<head>
    <title>防抖</title>
</head>
<body>
    <h1>防抖和节流:都是为了限制函数的执行次数。</h1>
    <h2>防抖:通过setTimeout的方式,在一定的时间间隔内,将多次触发变成一次触发</h2>
    <h2>如果短时间内大量触发同一事件,只会执行一次函数</h2>
    <h2>防抖实现的关键就在于setTimeout这个函数,由于还需要一个变量来保存计时,
        考虑维护全局纯净,可以借助闭包来实现</h2>
    <input type="text">
    <input type="submit" id="input">
    <script type="text/javascript">
        //通过id选择器获取到元素
        var btn = document.getElementById('input');
        // 对获取的元素进行事件监听 关于addEventListener要仔细看文档
        //遇到debounce(submit,2000) 就会执行这个debounce这个函数,形成闭包
        //并且会返回一个函数,这个函数每当按下按钮时就会触发。
        btn.addEventListener('click',debounce(submit,2000),false);
        function submit(){
            console.log(1);
        }     
        //第一次有延时处理
        function debounce(fn,wait){
            var timer = null;
            return function(){
                if(timer){
                    clearTimeout(timer);
                    timer = null;
                }
                timer = setTimeout(() => {
                    //通过apply解决原本this指向和事件对象的问题
                    //原本的this指向为btn,事件对象为
                    fn.apply(this,arguments);
                },wait);
            }
        }

        // 解决第一次延时处理的问题
        // function debounce(fn,wait){
        //     var timer = null;
        //     return function(){
        //         if(timer){
        //             clearTimeout(timer);
        //         }
        //         if(!timer){
        //             //这个this是指向哪里的
        //             console.log(this)
        //             console.log(arguments)
        //             fn.apply(this,arguments);
        //         }
        //         timer = setTimeout(()=>{
        //             timer = null;
        //         },wait);
        //     }
        // }

    </script>
</body>
</html>

15.节流

<!DOCTYPE html>
<html lang="en">
<head>
    <title>防抖(比节流好用)</title>
</head>
<body>
    <h1>防抖和节流:都是为了限制函数的执行次数。</h1>
    <h2>节流:减少一段时间的触发频率</h2>
    <input type="text">
    <input type="submit" id="input">
    <script type="text/javascript">
        var btn = document.getElementById('input');
        btn.addEventListener('click',throttle(submit,2000),false);
        function submit(){
            console.log(1);
        }
        function throttle(fn,delay){
            var begin = 0;
            //其实这里接受了触发事件的this和arguments
            return function(){
                //getTime()返回1970年1月1日距今的毫秒数
                var cur = new Date().getTime();
                if(cur - begin > delay){
                    //如果不执行下面这一步的话,fn()会指向window
                    //而原本fn()即sumbit是指向btn的
                    fn.apply(this,arguments);
                    begin = cur;
                }
            }
        }
    </script>
</body>
</html>

16.数组扁平化的方法

1.使用递归的方法,实现数组的扁平化

const flatten = (arr) => {
    let res = [];
    for(let i = 0; i < arr.length; i++){
        //如果arr的第i项是数组的话,就做递归
        //如果不是数组的话,就直接push进去
        if(Array.isArray(arr[i])){
            res = res.concat(flatten(arr[i]))
        }else{
            res.push(arr[i])
        }
    }
    return res
}
let arr = [1,[2,[3,4]]]
console.log(flatten(arr))

2.采用扩展运算符和some方法,两者共同使用达到数组扁平化的目的:

const flatten = (arr) => {
    //1.箭头函数如果不使用大括号,那么箭头后面只能有一行代码,
    //而且省略大括号会隐式的返回这行代码
    //2.some()方法,如果有一项函数返回true,
    //则这个方法返回true,否则返回false
    while(arr.some((item) => Array.isArray(item))){
        //3.concat()方法用于连接两个或者多个数组
        //arr.concat(arr1, arr2, ..., arrX)
        //其中,concat()的参数可以是具体的值也可以是数组
        //重点!!!如果要进行concat()操作的参数是数组,
        //那么添加的是数组的元素,而不是数组,但是只能解决一层的数组问题
        //4.扩展运算符...arr解构数组
        console.log(arr)
        arr = [].concat(...arr)
    }
    return arr;
}
let arr = [1,[2,[3,4]]]
console.log(flatten(arr))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值