数组的遍历
// 1.从后往前想,每次攻击完必然会持续 duration 的时间,所以一旦 timeSeries 的长度不为零,总是会
// 存在最后一次攻击存在 duration 的时间(对应第 10,11 行代码)
// 2.如果下一次攻击与上一次攻击的间隔时间小于 duration,则攻击时间有重合,重合的攻击时间会被合并到
// 下一次攻击 duration 中,按照从后往前想的原则,此时只需要记录两次攻击之间的间隔时间就可以了
// (因为下一次攻击的 duration 已经记录了)
// 3.如果下一次攻击与上一次攻击的间隔时间大于 duration,则完整记录 duration
// 4.以此类推,从最后一次攻击一直记录到第一次攻击
/**
* @param {number[]} timeSeries
* @param {number} duration
* @return {number}
*/
var findPoisonedDuration = function(timeSeries, duration) {
let time = 0
if(timeSeries.length) { // 记录最后一次攻击的持续时间
time = duration
}
for(let i = 1; i < timeSeries.length; i++) {
let distance = timeSeries[i] - timeSeries[i - 1]
time += Math.min(distance, duration)
}
return time
};
// 打擂台法,连续的个数大的保存,小的丢弃掉,重新记述
/**
* @param {number[]} nums
* @return {number}
*/
var findMaxConsecutiveOnes = function(nums) {
let count = 0, max = 0
for(let i = 0; i < nums.length; i++) {
if(nums[i] === 1) {
count++
} else {
if(max < count) {
max = count
}
count = 0
}
}
// 这里最后一次如果是最大的不要忘了比较
return max > count ? max : count
};
字符串
/**
* @param {string} a
* @param {string} b
* @return {number}
*/
var repeatedStringMatch = function(a, b) {
let m = new Map(), res = 1
// 首先把a中出现的字符统计一下
for(let i = 0; i < a.length; i++) {
let t = m.get(a[i])
m.set(a[i], t ? t + 1 : 1)
}
let k = Array.from(m.keys())
// 如果b中某个字符没有在a里面出现过,返回-1
for(let i = 0; i < b.length; i++) {
if (!k.includes(b[i])) {
return -1
}
}
let s = ''
// 如果b是s的字串,则s=a的尾部 + [b的一部分] + a的头部
while(s.length < a.length * 2 + b.length) {
// a重复res次,判断是否包含b
s = a.repeat(res++)
if (s.search(b) > -1) {
return res - 1
}
}
return -1
};
/**
* @param {string} s
* @return {boolean}
* s+s 包含了所有移动的字符串
* 比如abc, abcabc包含了bca cab,移动3次后才有abc;abababab包含了baba abab,移动不到4次就有abab
* 所以可以根据s+s去除首尾元素后判断是否包含自身
*/
var repeatedSubstringPattern = function(s) {
let str = (s + s).slice(1, -1)
return str.indexOf(s) === -1 ? false : true
};
/**
* @param {string} s
* @return {string}
* 将 s 翻转添加到 s 的前面,但是要去掉 s 末尾 与 s 开头相同的部分
* s = abc, temp = cba, temp[2] = s[0], res = cbabc
* s = aac, temp = caa, temp[1-2] = s[0-1], res = caac
*/
var shortestPalindrome = function(s) {
let temp = s.split('').reverse().join(''), res, i = 0
for(let i = s.length; i >= 0; i--) {
if (temp.slice(s.length - i) === s.slice(0, i)) {
return temp.substring(0, s.length - i) + s
}
}
return ''
};
// 还可以用 KMP 算法
/**
* @param {string} path
* @return {string}
*/
var simplifyPath = function(path) {
// 2个目录之间只能有一个 /
path = path.replace(/\/+/g, '/')
let arr = path.split('/')
for(let i = 0; i < arr.length; i++) {
// 如果是 ./ 则删除./
if (arr[i] === '.') {
arr.splice(i, 1)
i--
} else if (arr[i] === '..') {
// 如果是 ../ 则删除../和前一个
if (i === 0) {
arr.splice(i, 1)
i--
} else {
arr.splice(i - 1, 2)
i -= 2
}
}
}
let str = arr.join('/')
// 始终以 / 开头
if (str[0] !== '/') {
str = '/' + str
}
// 最后一个目录名不能以 / 结尾
if (str.length > 1 && str[str.length - 1] === '/') {
str = str.slice(0, -1)
}
return str
};
/**
* @param {string[]} tokens
* @return {number}
* 遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中
*/
var evalRPN = function(tokens) {
let stack = [], len = tokens.length
for(let i = 0; i < tokens.length; i++) {
let temp = Number(tokens[i])
if (!isNaN(temp)) {
stack.push(temp)
} else {
let y = stack.pop()
let x = stack.pop()
// 用括号将数字包裹起来,避免减-1时报错
stack.push(parseInt(eval(`(${x})${tokens[i]}(${y})`)))
}
}
return stack[0]
};
/**
* @param {string} s
* @return {number}
* 跟#150类似
*/
var calculate = function(s) {
let stack = []
// 去掉空格
s = s.replace(/\s+/g, '')
// 按运算符分开 并保留运算符
let arr = s.split(/([+\-\*\/])/)
for(let i = 0; i < arr.length; i++) {
if (arr[i] !== '/' && arr[i] !== '*') {
stack.push(arr[i])
} else {
// 如果是乘除 就先计算一下
let x = stack.pop()
let y = arr[i + 1]
stack.push(parseInt(eval(`${x}${arr[i]}${y}`)))
i++
}
}
return eval(stack.join(''))
};
/**
* @param {number} n
* @param {string[]} logs
* @return {number[]}
*/
var exclusiveTime = function(n, logs) {
// stack 如果是start就将 id 入栈,如果是end就出栈
// pre 前一个状态的位置
let arr = new Array(n).fill(0), stack = [], pre = 0
for(let i = 0; i < logs.length; i++) {
let temp = logs[i].split(':')
let id = temp[0], status = temp[1], time = temp[2]
if (status === 'start') {
// 如果是 start 状态就把时间差加到上一个函数中
if (stack.length) {
arr[stack[stack.length - 1]] += time - pre
}
pre = time
stack.push(id)
} else {
// 如果是 end 就把时间差加到当前函数上
arr[id] += time - pre + 1
pre = Number(time) + 1
stack.pop()
}
}
return arr
};
/**
* @param {string} s
* @return {string}
*/
var decodeString = function(s) {
while(s.includes('[')) {
s = s.replace(/(\d+)\[([A-Za-z]*)\]/, (match, p1, p2) => {
return p2.repeat(p1)
})
}
return s
};
链表
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @param {number} val
* @return {ListNode}
*/
var removeElements = function(head, val) {
if (!head) {
return head
}
head.next = removeElements(head.next, val)
return head.val === val ? head.next : head
};
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @param {number} n
* @return {ListNode}
*/
var removeNthFromEnd = function(head, n) {
if (!head || !head.next) {
return null
}
let p = head, q = head
// 快指针先走n步
while(n > 0) {
p = p.next
n--
}
// 删除的是第一个节点
if (!p) {
return head.next
}
while(p.next) {
p = p.next
q = q.next
}
// 删除倒数第n个节点
q.next = q.next.next
return head
};
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var swapPairs = function(head) {
if (!head || !head.next) {
return head
}
let next = head.next
head.next = swapPairs(next.next)
next.next = head
return next
};