1、最近在 LeetCode 看一些算法题 我只把题的名字列出来了, 大家有兴趣的可以在leetCode 自行搜索, 如果有更优的解题思路欢迎大家评论区讨论
反转字符串中的单词
Let's take LeetCode contest 需要输出的结果是 s'teL ekat edoCteeL tsetnoc
function revertByWorld(str) {
// 在需要 map 的前提下,需要把字符串 按照 空格拆分
return str.split(' ').map((item) => {
// 比如 item 为 Let's 时候 需要换成 s'teL 是要用到 反转, 所以又要转成数组, 最后的是把 [s'teL] 用join
return item.split('').reverse().join('')
}).join(' ')
}
revertByWorld('Let's take LeetCode contest')
计数二进制子串
'1010' 输出 2 因为 10 是不连续的子串 '1100' 输出2 因为 1100 是不连续的子串, 10 是不连续的子串
function countBinarySubstrings(str) {
str = str.split('')
// pre 前一个出现的次数, cur 当前出现的次数
let result = 0, pre = 0, cur = 1
for (let i = 0 ; i < str.length - 1; i++) {
if (str[i] === str[i+1]) {
// 当 i = 0 的时候 1 出现的两次
cur++
} else {
// 当 i = 1 时 会走到这里 pre 记录 上次 1 的两次
pre = cur
// 把当前的设置为 1
cur = 1
}
// 当 i== 1 的时候 第一次走到这里 其实就是走到了 110 这时候肯定至少符合一次了嘛 10
// 按照这个思路 可以在往里边套
if (pre >= cur) {
result++
}
}
return result
}
console.log(countBinarySubstrings("1100"))
电话号码组合
手机键盘有 9几个 数字键盘, 1 为空
let map = ['', 1, 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz']
对应 的数字 按照下标 0 1 2 3 ......
也就是说 我们输入 2 3 4 得到 'abc', 'def', 'ghi'
加入用户每次输入两个数字, 通过一个 外循环, 一个内循环就能解决掉这个问题呢, 但是输入 3 5 个数字 就不能这么解决了,也就是说我们不确定循环的次数
function letterCombinations(str) {
// 对输入做处理,如果小于1返回空(LeetCode测试用例)
if (str.length < 1) return []
// 建立电话号码键盘映射
let map = ['', 1, 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz']
let code = []
// code 找到对应的 字母
str.split('').map((item) => {
code.push(map[item].split(''))
})
if (code.length === 1) {
return code
}
function comb () {
let tmp = []
// 前两个的组合
for(let i = 0; i <= code[0].length - 1; i++) {
for(let j = 0; j <= code[1].length - 1; j++) {
tmp.push(`${code[0][i]}${code[1][j]}`)
}
}
// 这一步最重要 把前两个的组合替换掉 前两个 然后在和下一个 在做循环
code.splice(0, 2, tmp)
if (code.length > 1) {
// 接着个下一给做循环
comb()
} else {
return tmp
}
return code[0]
}
return comb()
}
console.log(letterCombinations("234"))
卡牌分组
[1,2,2,1,2,2] 返回true 因为可以拆分成 [1, 1], [2, 2], [2, 2] 把 4个 2 拆分成两组
[1,1,2,2,1,2,2] 返回 false 因为可以拆分成 [1, 1, 1], [2, 2, 2], [2] 多出来一个 2
也就是说每个的长度都是最少的倍数, 也就是说求几个数的最大公约数 (什么是 最大公约数 我也有专门的一篇博客)
function hasGroupsSizeX(arr) {
// sort 可以修改原数组
arr.sort()
let group = {}
// 求每个数组数显的次数
arr.map(((item) => {
group[item] = group[item] ? ++group[item] : 1
}))
// 辗转相除法 求最大公约数
function gcb (a, b) {
if (b === 0) {
return a
} else {
return gcb(b, a % b)
}
}
// 这里已经转成数组
group = Object.values(group)
while(group.length > 1) {
let [a, b] = [group.shift(), group.shift()]
let val = gcb(a, b)
if (val === 1) {
return false
} else {
// 这里很重要, 把两个比较完的最大公约数 和 下一个在做比较
group.unshift(val)
}
}
// group 最后只会剩下一个
return group.length ? group[0] > 1 : false
}
hasGroupsSizeX([1,2,2,1, 2, 2])
贪心算法
总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,算法得到的是在某种意义上的局部最优解
1、分发饼干
对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
function findContentChildren(g, s) {
// 一般情况下, 贪心算法首先需要排序
g.sort()
s.sort()
let i = 0 , j = 0, result = 0
// 大家想一个问题哈, 当 i j = 0 的时候 小孩是吃饱了, 当 i j = 1 的时候 小孩吃不饱
// 所以 只有在小孩吃不饱的情况下, 小孩不能变, 饼干要变
while(i <= g.length && j <= s.length) {
if (g[i] <= s[j++]) {
i++
result++
}
}
return result
}
findContentChildren([1, 3], [1, 2, 3])
2、摆动序列
如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为摆动序列。第一个差(如果存在的话)可能是正数或负数。少于两个元素的序列也是摆动序列。
function wiggleMaxLength(arr) {
if(arr.length <= 2) {
return arr.length
}
let result = 1, flag = 0 // flag 如果等于0 说明还没有摆动
let pre, cur
for (let i = 1; i < arr.length; i++) {
pre = arr[i - 1]
cur = arr[i]
// 这个很重要,比如 [2, 5, 3]
// 2 - 5 < 0 这时候 走到 if 后边的判断 flag < 0
// 5 - 3 > 0 flag < 0 走到 if 前边的判断 flag > 0 // result = 3
if ((pre - cur > 0 && flag <= 0) || (pre-cur < 0 && flag >=0)) {
// 每次都要更新 flag 的状态
flag = pre - cur
result++
}
}
return result
}
wiggleMaxLength([1,17])
移掉K位数字
移除 k 个数字之后 得到一个最小的数
举个栗子: 1445219 去掉 3 位 445 得到最小数字 1219 按照思路是 删除高位比较大的数字, 第一次循环 删除4, 第二次循环删除4, 第三次循环删除5, 每次都要从 0 的位置从新删除, 当 数字足够大, 而且删除的位数够多, 那这样的效率是很慢的
把 小的数字 推入栈内, 当前数字和栈内所有的元素对比, 大于 栈内的 元素呢, 推入栈内, 小于呢 退出顶部栈内的元素
function removekdingits(num, k) {
let n = num.length
if (n <= k) return '0'
let stack = []
for (let i = 0; i < n; i++) {
// 当前元素和栈内所有元素对比
while ( k && stack.length && num[i] < stack[stack.length - 1]) {
k--
stack.pop()
}
if ( stack.length || num[i] !== '0' ) { // 如果是 空栈, '0'就不要加入了
stack.push(num[i])
}
}
// 如果 k 还有值, 需要把最后的删除掉
while(k--) stack.pop()
return stack.join('') || '0'
};
removekdingits('114659', 3)