Open Linjiayu6 opened 4 years ago
var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10]
第一种实现
// 扁平化
let result = []
var flatten = array => {
array.forEach((item) => {
if (Object.prototype.toString.call(item) === '[object Array]') {
flatten(item)
} else {
result.push(item)
}
})
return result
}
var flat = flatten(arr)
/**
* 去重 new Set, 转数组
* 1. [... new Set([1, 2, 2]]
* 2. Array.from(new Set([1, 2, 2]))
*/
var unique = [...new Set(flat)]
console.log(unique)
// 升序
result = unique.sort((a, b) => a - b)
console.log(result)
第二种实现 🔥🔥🔥🔥🔥
// Infinity 拍平深度
Array.from(new Set(arr.flat(Infinity))).sort((a, b) => a - b)
第三种实现 toString() 🔥🔥🔥🔥🔥
[...new Set(arr.toString().split(',').sort((a, b) => a - b))].map(data => parseInt(data))
var arr = [1, 2, [3, 4, 5, [6, 7], 8], 9, 10, [11, [12, 13]]]
var result = []
while (arr && arr.length > 0) {
var data = arr.shift()
if (Array.isArray(data)) {
arr = data.concat(arr)
} else {
result.push(data)
}
}
console.log(result)
第一版
let a1 = ['A1', 'A2', 'B1', 'B2', 'C1', 'C2', 'D1', 'D2']
let a2 = ['A', 'B', 'C', 'D'].map((item) => item + 3)
var result = a1.concat(a2).sort().map( => d.indexOf('3') > -1 ? d.replace('3', '') : d)
第二版
/**
* 两个数组合并成一个数组
* 请把两个数组 ['A1', 'A2', 'B1', 'B2', 'C1', 'C2', 'D1', 'D2'] 和 ['A', 'B', 'C', 'D']
* 合并为 ['A1', 'A2', 'A', 'B1', 'B2', 'B', 'C1', 'C2', 'C', 'D1', 'D2', 'D']
*/
var arr1 = ["A1", "A2", "B1", "B2", "C1", "C2", "D1", "D2"]
var arr2 = ["A", "B", "C", "D"]
function merge () {
// 先将所有的值后面加上 '3'
arr2.map(item => item + '3')
// 两个数组合并, 排序, sort是按照 A, A1, A2, B, B1, ... 方式排序
// 因为前面加上了'3', A1, A2, A3, B1, ...
var result = arr1.concat(arr2).sort().map(str => {
if (str.indexOf('3') > -1) { // 'A3'.indexOf('3') replace掉
str = str.replace('3', '')
}
return str
})
return result
}
merge()
for (var i = 0; i< 10; i++){ setTimeout(() => console.log(i) , 1000) }
本质: 异步流程,再执行i会丢失
1. setTimeout 第三个参数 作为回调函数的 参数传入
for (var i = 0; i< 10; i++) {
// function (i) 不要忘记
setTimeout(function (i) { console.log(i) }, 1000, i)
}
2. 绑定当前作用域, 将值传入
for (var i = 0; i< 10; i++) {
const fn = function (i) { console.log(i) }
setTimeout(fn.bind(Object.create(null), i), 1000)
}
3. IIFE 函数自己执行, 将值传入
for (var i = 0; i< 10; i++) {
(function (i) {
setTimeout(function () { console.log(i) }, 1000)
})(i)
}
4. 利用 let 块级作用域
for (let i = 0; i< 10; i++) {
setTimeout(() => console.log(i), 1000)
}
// 同上
for (let i = 0; i< 10; i++) {
let _i = i
setTimeout(() => console.log(_i), 1000)
}
// 下面代码中 a 在什么情况下会打印 1?
var a = ?;
if(a == 1 && a == 2 && a == 3){
console.log(1);
}
隐式转换, == 是toString方法的转换, 每次判断+1 就可以通过了。
var a = {
i: 1,
toString: function () { return a.i ++ }
}
if(a == 1 && a == 2 && a == 3){
console.log(1);
}
sleep(1000) 意味着等待1000毫秒
function sleep (timer) {
return new Promise(resolve => {
setTimeout(() => {
resolve(timer)
}, timer)
})
}
sleep(2000).then(timer => console.log(timer + ' success'))
// 2. 回调实现
function sleep (timer, cb) {
setTimeout(() => {
cb && cb(timer)
}, timer)
}
sleep(1000, (timer) => console.log(timer + ' success'))
fn().next().value.then...
function* sleep (timer) {
yield new Promise(resolve => setTimeout(() => {
resolve(timer)
}, timer))
}
sleep(2000)
.next().value // next执行, data.value 返回的是promise
.then(timer => console.log(timer + ' success'))
var g = sleep(2000)
g.next().value.then(console.log)
async function sleep (timer) {
let data = await new Promise(resolve => setTimeout(() => { resolve(timer) }, timer))
console.log(data)
return data // 必须用return 才能用then
}
sleep(2000)
.then(timer => console.log(timer + ' success'))
// 或者
var result = await sleep(2000)
console.log('result: ', result)
Number.prototype.add = function (num) {
// console.log(this) // Number{5}
return this.valueOf() + num
}
Number.prototype.minus = function (num) { return this.valueOf() - num }
/**
* 冒泡
* [3, 4, 1, 2]
* 每次把最大的值, 冒泡到最后面
* 1. [3, 1, 2, 4]
* 2. [1, 2, 3, 4]
* 3. [1, 2, 3, 4]
*/
function bubbleSort (arr) {
for (let i = 0; i < arr.length; i++) {
let num = 0
for (let j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
num += 1
var temp = arr[j]
arr[j] = arr[j + 1]
arr[j + 1] = temp
}
}
// 遍历一次没有再交换的则结束
if (num === 0) {
return arr
}
}
return arr
}
bubbleSort([3, 4, 1, 2])
Array.from({ length: 12 }) // 长度为12的数组, 值为 [undefined, undefined, undefined, ....]
Array.from({ length: 12 }).map((_, i) => obj[i + 1] || null)
/**
* { 1:222, 2:123, 5:888}
* 请把数据处理为如下结构: [222, 123, null, null, 888, null, null, null, null, null, null, null]
*/
var month = { 1:222, 2:123, 5:888}
var result = []
for (let i = 0; i < 12; i ++) {
result.push(null)
}
Object.keys(month).forEach(item => result[item - 1] = month[item])
思路:
任务有异步和同步, 任务如何串联起来执行?
xxx.xxxx.xxx 每个函数通过this返回, 将任务连接, 放到队列后
最后利用 宏队列或微队列特性, 滞后执行
// LazyMan('Tony');
// // Hi I am Tony
// LazyMan('Tony').sleep(10).eat('lunch');
// // Hi I am Tony
// // 等待了10秒...
// // I am eating lunch
// LazyMan('Tony').eat('lunch').sleep(10).eat('dinner');
// // Hi I am Tony
// // I am eating lunch
// // 等待了10秒...
// // I am eating diner
// LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');
// // Hi I am Tony
// // 等待了5秒...
// // I am eating lunch
// // I am eating dinner
// // 等待了10秒...
// // I am eating junk food
class _LazyMan {
constructor (name) {
this.name = name
this.queue = [] // 队列内容注册
this._init()
// 等到所有同步注册任务完事儿后, 我们再执行队列里的内容
// 用宏任务 或 微任务处理
Promise.resolve().then(() => this._next())
// 或 setTimeout(() => this._next(), 0)
return this
}
_init () {
console.log('Hi I am ' + this.name)
}
eat (food) {
const fn = () => {
console.log('I am eating ' + food)
this._next() // 执行下一个任务
}
this.queue.push(fn) // 先把任务放到队列里面, 等到所有注册完再去执行
return this
}
// 异步任务的统一处理
_async (delay) {
return () => new Promise(resolve => {
setTimeout(() => resolve(delay), delay * 1000)
}).then(data => {
console.log('等待了' + data + '秒')
this._next() // 执行下一个任务
})
}
// 异步的任务
sleep (delay) {
this.queue.push(this._async(delay))
return this
}
// 该异步任务会插到最前面
sleepFirst (delay) {
this.queue.unshift(this._async(delay))
return this
}
_next () {
if (this.queue && this.queue.length > 0) {
const task = this.queue.shift() // 从头移出来一个任务 执行
task && task()
}
}
}
const LazyMan = (name) => new _LazyMan(name)
LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');
1. 数据字典 + 计数
// nums1 = [1, 2, 2, 1] nums2 = [2, 2] 返回 [2, 2]
function match (nums1, nums2) {
var dictionary = {}
for (let i = 0; i < nums1.length; i++) {
if (dictionary[nums1[i]]) {
dictionary[nums1[i]] += 1
} else {
dictionary[nums1[i]] = 1
}
}
var result = []
nums2.forEach(d => {
if (dictionary[d] && dictionary[d] > 0) {
result.push(d)
dictionary[d] -= 1
}
})
return result
}
match([1, 2, 2, 1, 2], [2, 2])
2. 匹配
function match (nums1, nums2) {
var i = 0 // nums1
var result = []
while (i < nums1.length && nums2 && nums2.length > 0) {
if (nums2.indexOf(nums1[i]) > -1) {
nums2 = nums2.slice(nums2.indexOf(nums1[i]) + 1)
result.push(nums1[i])
}
i += 1
}
return result
}
// 0.7.21 写的
function jiaoji(nums1, nums2) {
var result = []
while (nums2.length > 0) {
var data = nums2.shift()
if (nums1.indexOf(data) > - 1) {
result.push(data)
nums1.splice(nums1.indexOf(data), 1)
}
}
return result
}
http://muyiy.cn/question/program/63.html
实现原理是 1 -> 2 -> 3 -> 4 在图像切换的时候, 切换到4, 后面没有元素的, 讲道理是1的现实。
通过赋值 1, 4的图片
4假 -> 真1 -> 2 -> 3 -> 真4 -> 1假
在 4 -> 1假 这种过度效果中, 做到无缝, 等到1浮现后, 再切换为真1
http://muyiy.cn/question/program/67.html
/**
* 随机创建数组
* 1. Array.from({ length: 个数 }): [undefined, undefined, ...]
* 2. 随机数取整数 Math.floor(Math.random() * base) base = 100 基于0 - 100的随机数创建
*/
var createList = (length, base = 100) => Array.from({ length }).map(() => Math.floor((Math.random() * base)))
// 排序
var list = createList(10, 100).sort((a, b) => a - b)
// 去重
list = Array.from(new Set(list))
// 连着的放在一起
var sequence = list => {
var result = []
var temp = []
list.forEach(d => {
if (temp && temp.length === 0) {
temp.push(d)
} else {
if (temp[temp.length - 1] + 1 === d) { // 如果连续就放到暂存栈中
temp.push(d)
} else {
result.push(temp) // 不连续直接输出
temp = [d]
}
}
})
result.push(temp)
return result
}
function fn (string) {
let result = ''
for (let i = 0; i < string.length; i++) {
var s = string[i]
result += s === s.toUpperCase() ? s.toLowerCase() : s.toUpperCase()
}
return result
}
正则表达式
string.replace(/(\w)/g, (s) => s === s.toUpperCase() ? s.toLowerCase() : s.toUpperCase())
str.replace(/[a-zA-Z]/g, a => a.toUpperCase() === a ? a.toLowerCase() : a.toUpperCase())
从长度为 n 的字符串 S 中,查找是否存在字符串 T,T 的长度是 m,若存在返回所在位置 http://muyiy.cn/question/program/71.html
1 - S.match(T) api方式match
function _match (S, T) {
var index = S.match(T).index
return index ? index : 0
}
_match('eabced', 'ed')
2 - S.search(T) const _math = (S, T) => S.search(T)
3. - indexOf('') + slice
function match(S, T) {
if (S.length < T.length) return -1;
if (S.indexOf(T[0]) < 0) return -1;
var pos = S.indexOf(T[0]);
return S.slice(pos, pos + T.length) === T ? pos : -1;
}
match('qasxffff', 'fff');
- 问题在于: onclick ✨ 写不明白
<html>
<body>
<div id="key">0</div>
<!-- onclick="increase()" 这个地方竟然错了 -->
<button onclick="increase()">increase</button>
<button onclick="decrease()">decrease</button>
<script>
const data = { count: 0 }
const proxy = new Proxy(data, {
set: function (obj, property, value) {
obj[property] = value
console.log('set', obj)
render(value)
},
get: function (obj, property) {
return obj[property]
}
})
function render (value) {
document.getElementById('key').innerHTML = value
}
function increase () {
proxy.count += 1
}
function decrease () {
proxy.count -= 1
}
</script>
</body>
</html>
// list.slice(0, key) 截取值是 0, 1, .... key - 1
var rotate = function(nums, k) {
var len = nums.length
if (len === 0 || len === 1 || k === 0) return nums
k = k > len ? k : k % len
nums = nums.slice(len - k).concat(nums.slice(0, len - k))
return nums
};
/**
* @param {number[]} nums
* @param {number} k
* @return {void} Do not return anything, modify nums in-place instead.
*/
var rotate = function(nums, k) {
var len = nums.length
if (len === 0 || len === 1 || k === 0) return nums
k = k > len ? k : k % len
// 原地不动类型
for (let i = 0; i < k; i++) {
// var data = nums.splice(len - 1, 1) // 这个ok, 但是会超时 从队尾删除
var data = nums.pop() // 从队尾删除
nums.unshift(data) // 从队头增加
}
return nums
};
http://muyiy.cn/question/program/81.html
function match (base = 100) {
let result = []
for (let i = 1; i <= base; i++) {
if (i < 10) continue
let str = i.toString()
let re_str = str.split('').reverse().join('') // 回文判断
if (str === re_str) {
result.push(i)
}
}
return result
}
/**
* 1. 个数肯定都是
* 2. 十位数 11 的倍数
* 3. 101, 111, 121 ...
* - 101 * i + n * 10 (n = 0 ~ 9)
* - 101 * 2 * i + n * 10
*
* 4. 1001, 1111, 1221 ...
* - 1001 * i + n * 110
* - 1001 * 2 * i + n * 110
*/
function fn () {
let result = []
for (let i = 1; i < 10; i++) {
result.push(i) // 1位数所有都是
result.push(i * 11) // 十位数 11倍数
for (let j = 0; j < 10; j++) {
result.push(i * 101 + j * 10)
result.push(i * 1001 + j * 110)
}
}
return result
}
fn()
测试用例注意[0, 0, 1]
var moveZeroes = function(nums) {
var _len = nums.length
if (_len === 0 || _len === 1) return nums
var _zeronums = 0
var i = 0
while (i < _len - _zeronums) {
if (nums[i] === 0) {
nums.splice(i, 1)
nums.push(0)
_zeronums += 1
// * 总错: i不会进位, 是根据当前位置再做判断 [0, 0, 1]
} else {
i += 1
}
}
return nums
};
var swap = function (nums, i, j) {
var temp = nums[i]
nums[i] = nums[j]
nums[j] = temp
}
var moveZeroes = function(nums) {
if (nums.length < 1) return nums
var zeros = 0
for (let i = 0; i < nums.length - zeros; i++) {
if (nums[i] === 0) {
for (let j = i; j < nums.length - 1 - zeros; j ++) {
swap(nums, j, j + 1)
}
zeros += 1
}
}
return nums
};
http://muyiy.cn/question/program/84.html
function add (...args1) {
var store = args1
function fn (...args2) {
if (args2.length === 0) {
return store.reduce((a, b) => a + b, 0)
}
store = store.concat(args2)
return fn
}
return fn
}
add(1, 2, 3)()
add(1)(2)(3)()
add(1)(2, 3)()
/**
* add(1); // 1
add(1)(2); // 3
add(1)(2)(3); // 6
add(1)(2, 3); // 6
add(1, 2)(3); // 6
add(1, 2, 3); // 6
*/
function add () {
// 1. 对参数进行汇总入栈
let params = Array.prototype.slice.call(arguments, 0)
function addArgs (...args) {
params = params.concat(args)
return addArgs
}
// 2. 这里是重点 直接可以读到toString 转换方法
addArgs.toString = () => params.reduce((a, b) => a + b, 0)
return addArgs
}
👧 forEach是没有办法停止的, 就是不要用forEach
function add (arr, target) {
var map = {}
for (let i = 0; i < arr.length; i ++) {
var data = arr[i]
if (map[target - data]) {
return [map[target - data], i]
}
map[data] = i
}
return []
}
直接 new URL(xxx) 判断
function isUrl (url) {
try {
new URL(url)
return true
} catch (error) {
return false
}
}
https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/143
用 JavaScript 写一个函数,输入 int 型,返回整数逆序后的字符串。如:输入整型 1234,返回字符串“4321”。要求必须使用递归函数调用,不能用全局变量,输入函数必须只有一个参数传入,必须返回字符串
// 1234
function reverse(num) {
let result = ''
let string = num.toString() // 转为string
if (string.length === 0 || string.length === 1) return string
function fn (string, i) {
if (i === -1) return result
result += string[i]
return fn(string, i - 1)
}
return fn(string, string.length - 1)
}
// 如何求解?
function print(n){
setTimeout(() => {
console.log(n);
}, Math.floor(Math.random() * 1000));
}
for(var i = 0; i < 100; i++){
print(i);
}
function print(n){
// 自执行 (n => fn)(n)
setTimeout(((n) => {
console.log(n);
})(n), Math.floor(Math.random() * 1000));
}
for(var i = 0; i < 100; i++){
print(i);
}
function print(n){
setTimeout(() => {
console.log(n);
}, 0 * Math.floor(Math.random() * 1000));
}
for(var i = 0; i < 100; i++){
print(i);
}
http://muyiy.cn/question/program/102.html
function seven (num) {
let result = num
// for (let i = 0; i < 3; i++) {
// result = result << 1
// }
result = result << 3
return result - num
}
/**
* getItem
* setItem
* clear
* removeItem
* key
* length
*/
class LocalStorage {
constructor () {
this.LS = {}
}
getItem (key) {
return this.LS[key] || null
}
setItem (key, value) {
this.LS[key] = value
}
clear () {
this.LS = {}
}
removeItem (key) {
delete this.LS[key]
}
key () {
return Object.keys(this.LS)
}
length () {
return Object.keys(this.LS).length
}
}
// 挂在到 window下
window.LS = new LocalStorage()
LS.setItem('a', { a : 1})
LS.getItem('a')
LS.setItem('b', { b : 1})
LS.setItem('a', document.body)
LS.getItem('a')
LS.length()
LS.key()
LS.clear()
/**
* new Date() Wed Jul 15 2020 10:37:16 GMT+0800 (China Standard Time)
* new Date().valueOf() 当前时间 1594780608433
* Date.now() 当前时间 1594780615144
*/
class LS {
constructor () {
this.cache = new Map() // key, value
this.date = new Map() // key, date 当超过时间, 则清除 cache里内容
}
setItem (key, value, time) {
this.date.set(key, time)
this.cache.set(key, value)
console.log(this.date)
console.log(this.cache)
}
getItem (key) {
this.check(key)
return this.cache.get(key) || - 1
}
delete (key) {
this.cache.delete(key)
}
check (key) {
// 时间验证
if (this.date.has(key)) {
// 时间存进去是 number类型
if (Date.now() > this.date.get(key)) {
this.cache.delete(key)
this.date.delete(key)
return false // 已经删除
}
return true // 可以继续用
}
return false
}
clear () {
this.cache.clear()
this.date.clear()
}
}
window.cache = new LS()
window.cache.setItem('a', 'aaaaa', Date.now() + 10000) // 当前时间加上10s后过期
window.cache.getItem('a') // 当前时间加上10s后过期
1. 又臭又长版本
function fn (url) {
var params = url.split('?')[1]
if (params) {
params = params.split('&')
var result = ''
for (let i = 0; i < params.length; i ++) {
if (params[i].indexOf('elective') > -1) {
result = params[i]
break
}
}
result = result.split('=')[1]
return result ? result.split(',') : []
}
return []
}
fn('https://www.xx.cn/api?keyword=&level1=&local_batch_id=&elective=&local_province_id=33')
2. new URL() 获取
function fn (url, key) {
// search: ?keyword=&level1=&local_batch_id=&elective=800,700&local_province_id=33
// searchParams.get(key) 获取
return new URL(url).searchParams.get(key) // 800,700
}
fn('https://www.xx.cn/api?keyword=&level1=&local_batch_id=&elective=800,700&local_province_id=33', 'elective')
3. 正则表达 🔥🔥🔥🔥🔥
var str = 'https://www.baidu.com/auth?a=1&bizId=310015,7801&b=3'
// 目标所有参数匹配: 前可能有?(匹配)=(匹配)后可能有&
var pattern = /\??(\w+)=(\w+)\$?/g
str.match(pattern) // ["?a=1", "bizId=310015", "b=3"]
// 模式匹配 (字母数字 多次)=(字母数字 多次) 但是没有匹配到, 内容
var pattern = /(\w+)=(\w+)/g
str.match(pattern) // ["a=1", "bizId=310015", "b=3"]
var pattern = /(\w+)=(\w+)(,\w+)?/g
str.match(pattern) // ["a=1", "bizId=310015,7801", "b=3"]
var pattern = /(bizId)=(\w+)(,\w+)?/g
str.match(pattern) // ["bizId=310015,7801"]
function fn () {
var str = 'https://www.xx.cn/api?keyword=&level1=&local_batch_id=&elective=800,700&local_province_id=33'
var pattern = /elective=(\w*)(,\w+)?/g
var data = str.match(pattern) // ["elective="] ["elective=800"] ["elective=800,700"]
if (data) {
return data[0].split('=')[1].split(',')
}
return []
}
// 输出 '1~3, 5, 7~8, 10'
function fn(str) {
// 输入 '1, 2, 3, 5, 7, 8, 10'
// 输出 '1~3, 5, 7~8, 10'
var arr = str.split(',').map(d => Number(d)).sort((a, b) => a - b);
var result = [];
var j = 0;
// 这里是等于, 总错
for (let i = 1; i <= arr.length; i++) {
if (arr[i] !== arr[i - 1] + 1) {
if (i - 1 === j) {
result.push(arr[j].toString());
} else {
result.push(arr[j] + '~' + arr[i - 1]);
}
j = i;
}
}
return result;
}
fn('1, 2, 3, 5, 7, 8, 10');
var entry = {
a: {
b: {
c: {
dd: 'abcdd'
}
},
d: {
xx: 'adxx'
},
e: 'ae'
}
}
// 要求转换成如下对象
var output = {
'a.b.c.dd': 'abcdd',
'a.d.xx': 'adxx',
'a.e': 'ae'
}
function fn (entry, prefix = '', result = {}) {
Object.keys(entry).forEach(id => {
var data = entry[id]
prefix = prefix ? prefix + '.' + id : id
// 类型判断
if (Object.prototype.toString.call(data) === '[object Object]') {
fn(data, prefix, result)
} else {
result[prefix] = data
}
})
return result
}
fn(entry)
// [123, "meili", "123", "mogu", 123] => [123, "meili", "123", "mogu"]
// [123, [1, 2, 3], [1, "2", 3], [1, 2, 3], "meili"] => [123, [1, 2, 3], [1, "2", 3], "meili"]
// [123, {a: 1}, {a: {b: 1}}, {a: "1"}, {a: {b: 1}}, "meili"] => [123, {a: 1}, {a: {b: 1}}, {a: "1"}, "meili"]
function fn (list) {
var map = new Map()
// 基本类型过滤掉
list = [...new Set(list)]
// 引用类型过滤
/**
* JSON.stringify([1, "2", 3]) => "[1,"2",3]"
* JSON.stringify([1, 2, 3]) => "[1,2,3]"
*/
list.forEach(value => {
var key = JSON.stringify(value)
if (!map.has(key)) {
map.set(key, value)
}
})
// 转为数组类型
return [...map.values()]
}
function fn (list) {
var map = new Map()
// 基本类型过滤掉
list = [...new Set(list)]
// 引用类型过滤
/**
* JSON.stringify([1, "2", 3]) => "[1,"2",3]"
* JSON.stringify([1, 2, 3]) => "[1,2,3]"
*/
list.forEach(value => {
var key = JSON.stringify(value)
if (!map.has(key)) {
map.set(key, value)
}
})
// 转为数组类型
return [...map.values()]
}
1- 硬写模式
// 'abcaakjbb' => { 'a': 2, 'b': 2 }
// 'abbkejsbcccwqaa' => { 'c': 3 }
/**
* i, j 指针
* i和j值相同, 则i不动, 继续 j += 1
* i和j值不同, 则 j - i 数量返回, i = j, j += 1
*/
function fn (str) {
var map = new Map()
var i = 0, j = 1
var _max = 0 // 暂存最大值
while (i < str.length && j <= str.length) {
if (str[i] === str[j]) {
j += 1
} else {
var val = str[i]
if (map.has(val)) {
map.set(val, Math.max(map.get(val), j - i))
} else {
map.set(val, j - i)
}
_max = Math.max(_max, map.get(val))
i = j
j += 1
}
}
// 在map基础上 选最大值
var result = {}
var values = [...map.values()]
var keys = [...map.keys()]
values.forEach((val, i) => {
if (val === _max) {
result[keys[i]] = val
}
});
return result
}
fn('abcaakjbb')
fn('abbkejsbcccwqaa')
2 - 正则模式
// 概念
/**
* 输出: ["a", "b", "c", "a", "11", "aaaa", "k", "j", "bbbbb"]
* (\w) 所有字符和数组类型, ()代表分组概念
* \1 代表括号内容匹配, 匹配重现
*
* 该正则 找连续重复
*/
var str = 'abca11aaaakjbbbbb'
str.match(/(\w)\1*/g)
var str1 = 'abacabcxjabc'
str1.match(/(abc)\1*/g) // ["abc", "abc"]
function fn (str) {
// 字符串连续匹配 ["a", "b", "c", "a", "11", "aaaa", "k", "j", "bbbbb"]
var arr = str.match(/(\w)\1*/g)
var arrLen = [] // 每个字符串的长度
var _maxLen = 0 // 最大长度
arr.forEach(item => {
arrLen.push(item.length)
_maxLen = Math.max(_maxLen, item.length)
})
var result = {}
arrLen.forEach((value, index) => {
if (value === _maxLen) { result[arr[index][0]] = value }
})
return result
}
fn('abbkejsbcccwqaa')
/**
* 有一堆扑克牌,将牌堆第一张放到桌子上,再将接下来的牌堆的第一张放到牌底,如此往复;
* 最后桌子上的牌顺序为: (牌底) 1,2,3,4,5,6,7,8,9,10,11,12,13 (牌顶);
* 问:原来那堆牌的顺序,用函数实现
*
* a, b, c, d
* [a] 单数是 pop
* [b, a] 双数是 shift
* [b, a, c] 单数是 pop [c, d]
* [d, b, a, c] 双数是 shift [d]
* 倒着推理
*/
// 恢复原来顺序
function reverseToNormal (pocker) {
var result = []
while (pocker && pocker.length > 0) {
var data = null
if (pocker.length % 2 === 1) { // 奇数
data = pocker.pop() // 从尾出栈
} else {
data = pocker.shift() // 从头出栈
}
result.unshift(data)
}
// 结果 [7, 6, 8, 5, 9, 4, 10, 3, 11, 2, 12, 1, 13]
return result
}
reverseToNormal([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13])
/**
* [a, b, c, d]
* [], 偶数 => [a]
* [a], 奇数 => [b, a] unshift(data)
* [b, a], 偶数 => [b, a, c] push(data)
* [b, a, c], 奇数 => [d, b, a, c] unshift(data)
*/
function toReverse (pocker) {
var result = []
pocker.forEach(data => {
if (result.length % 2 === 1) { // 奇数
result.unshift(data)
} else {
result.push(data)
}
})
return result
}
toReverse([7, 6, 8, 5, 9, 4, 10, 3, 11, 2, 12, 1, 13])
/**
* 在一个字符串数组中有红、黄、蓝三种颜色的球,且个数不相等、顺序不一致,请为该数组排序。
* 使得排序后数组中球的顺序为:黄、红、蓝。
* 例如:红蓝蓝黄红黄蓝红红黄红,排序后为:黄黄黄红红红红红蓝蓝蓝
*
* 1. 分桶, 得出每个颜色的内容
* 2. 桶拼接
*/
// 方案 1
function fn (str) {
var yellow = [], red = [], blue = []
for (var i = 0; i < str.length; i++) {
var data = str[i]
if (data === '黄') yellow.push(data)
if (data === '红') red.push(data)
if (data === '蓝') blue.push(data)
}
return yellow.concat(red).concat(blue).join('')
}
fn('红蓝蓝黄红黄蓝红红黄红')
// 方案 2
function fn (str) {
var yellow = 0, red = 0, blue = 0
for (var i = 0; i < str.length; i++) {
var data = str[i]
if (data === '黄') yellow += 1
if (data === '红') red += 1
if (data === '蓝') blue += 1
}
// '黄'.repeat(3) = '黄黄黄'
return '黄'.repeat(yellow) + '红'.repeat(red) + '蓝'.repeat(blue)
}
fn('红蓝蓝黄红黄蓝红红黄红')
// 方案 3
function fn (str) {
var rule = { '黄': 0, '红': 1, '蓝': 2 }
// 值小的, 在前面
return str.split('').sort((a, b) => rule[a] - rule[b]).join('')
}
fn('红蓝蓝黄红黄蓝红红黄红')
1 - reduce
function intersection(...args) {
// 前面 & 后面 => 新前面(交集) => 新前面 & 后面 => ...
var result = [...args].reduce((prev, curr) => {
// 前面根据后面内容, filter保留下来交集内容
return prev.filter(d => curr.includes(d));
});
return [...new Set(result)];
}
intersection([2, 1, 2], [1, 2, 3], [2, 5, 6, 6, 3]);
intersection([2, 10, 1], [1, 2, 3], [2, 5, 6, 6, 3], [10, 1]);
2 - 不用reduce
function intersection(...args) {
var result = [...new Set(args[0])];
for (let i = 1; i < args.length; i++) {
// result = [1, 2, 3] args[i] = [2, 2, 1] => result 为 [2, 1]
result = result.filter(data => args[i].includes(data));
}
return result;
}
1 - 字符串匹配
// 将 '10000000000' 形式的字符串,以每 3 位进行分隔展示 '10.000.000.000'
function fn(str) {
var arr = str.split('').reverse(); // 逆着来
var i = 0;
var result = [];
while (i < arr.length) {
result.push(arr.slice(i, i + 3).reverse().join(''));
i += 3;
}
return result.reverse().join('.');
}
fn('101000000304');
1. match
function _indexOf(S, T) {
return S.match(T) ? S.match(T).index : -1;
}
_indexOf('abcdesadfafa', '123')
_indexOf('abcdesadfafa', 'desa')
_indexOf('abcdesadfafa', 'ff')
2. slice
function _indexOf(S, T) {
for (let i = 0; i < S.length; i++) {
let j = 0;
if (S[i] === T[j]) {
if (S.slice(i, i + T.length) === T) return i;
}
}
return -1;
}
3. 基础实现
// arr 或 长string, matchstr, startIndex从指定索引开始, 默认为0
function indexOf (arr, matchstr, startIndex = 0) {
if (startIndex < 0) return -1
if (startIndex >= arr.length) return -1
for (var i = startIndex; i < arr.length; i++) {
if (arr[i] === matchstr) return i
}
return -1
}
_indexOf('stest', 'st'); _indexOf('stest', 'es'); _indexOf('stest', 'tex');
1- 深度优先和广度优先搜索实现 TODO