目录
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))