LeetCode
出现1的时候就记录1的索引,然后和之前出现1的索引位置进行比较,遍历完的最大值就是要找的值。
/**
* @param {number} n
* @return {number}
*/
const binaryGap = function(n) {
let temp = n.toString(2)
let res = 0
for (let i = 0,preIndex=0; i < temp.length; i++) {
if (temp[i]==='1'){
res = Math.max(res,i-preIndex)
preIndex = i
}
}
return res
};
console.log(binaryGap(22))
LeetCode链接
字典序样例
比如n=123 那么输出结果为
1,10,100,101109,11,110119,12,120123,13,1419,2,20,21.
整体思路
对于一个整数num,字典排序树的情况对应下边几种情况
如果一个数需要取中间的值可以 num >> 1右移一位 向下取整
const lexicalOrder = (n) => {
let res = []
// 最小的字典数,先放入数组
let num = 1
// 控制放入n个数字
for (var i = 0; i < n; i++) {
res.push(num)
// num后边加0还符合要求就直接放入
if (num * 10 <= n) {
num *= 10
} else {
// 不符合要求就先判断是否,到了对后一个字典数
// 如果没到就num++ 然后push进答案数组中,假如到了最后,就回退到上一个数字. 比如n=120 此时num=109 则需要让num变成11、或者n=123此时num=123 则需要让num=13
while (num % 10 === 9 || num + 1 > n) {
num = Math.floor(num/10)
}
num++
}
}
return res
}
LeetCode链接
遍历两个链表,直接在对应的数值相加,假如某个链表为空,可以用0代替它的数值相加。根据题意
可以知道相加的规则为:
需要注意当链表结束遍历的时候进位的数值为1则需要在链表的结尾加入值为1的节点
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} l1
* @param {ListNode} l2
* @return {ListNode}
*/
const addTwoNumbers = function(l1, l2) {
/**
* 当时以为js不能新建链表然后再新链表上操作,因为报出了内存溢出的错误,后来发现是后边的判断条件出现了错误
* @type {ListNode}
*/
// 创建新链表用于存放结果
let newNode = new ListNode()
let temp = newNode
let carry = 0
while (l1!==null||l2!==null) {
let x = l1 === null ? 0:l1.val
let y = l2 === null ? 0:l2.val
let sum = x + y + carry
/**
* 注意点: sum/10 再js中不会自动向下取整 所以需要Math函数
* @type {number}
*/
carry = Math.floor(sum/10)
sum = sum%10
temp.next = new ListNode(sum)
temp = temp.next
/**
* 这个判断条件为链表不为空
*/
if (l1) {
l1 = l1.next
}
if (l2) {
l2 = l2.next
}
if (carry===1) {
temp.next = new ListNode(carry)
}
}
return newNode.next
};
LeetCode链接
大致方法:用栈来维护结果字符串的长度,按照层级遍历。
String.prototype.split方法
// 传入一个要分割的字符返回分割后的数组
String.prototype.split()
/**
* @param {string} input
* @return {number}
*/
const lengthLongestPath = function (input) {
let res = 0
let stack = []
stack.push(0)
let newString = input.split('\n')
for (let i = 0; i < newString.length; i++) {
// 确定当前文件的层级,当没有/t的时候返回-1,说明文件在0级。
// 需要注意的是lastIndexOf
let level = newString[i].lastIndexOf('\t') + 1
/**
* 较难理解的部分
*/
while (stack.length - level > 1) {
stack.pop()
}
// \t\tsubsubdir1 这个字符串的长度为出去\之后的长度,计算length的时候需要减去层数补上1 也就是说长度为subsubdir1/ 这个/是算在字符串长度中的
// 后边的加1表示/这个符号
let length = stack[stack.length - 1] + (newString[i].length - level + 1)
console.log(newString[i])
stack.push(length)
if (newString[i].includes('.')) {
// 这个-1是为了把/这个符号的长度给去掉,因为是最后一个文件所以没/
res = Math.max(res, length - 1)
}
}
return res
};
LeetCode链接
解法1:用数组模拟队列,并遍历字符串s,假如当前遍历的字符串在前边没有出现过则就queue.push()进栈,假如出现过就需要删除队列前边的元素, 不断迭代,计算最大值。
解法2:采用滑动窗口的方式
/**
* @param {string} s
* @return {number}
* 解法1:采用队列的方法动态删除
*/
const lengthOfLongestSubstring = function (s) {
let queue = []
let res = 0
for (const sElement of s) {
// 或者写成if判断语句
/*
if(queue.includes(sElement)) {
第二个参数为删除元素的个数,为索引值+1
queue.splice(0,queue.indexOf(sElement)+1)
}
*/
while (queue.includes(sElement)) {
queue.shift()
}
queue.push(sElement)
res = Math.max(queue.length, res)
}
return res
};
/**
* 解法2:滑动窗口
* @param s
* @return {number}
*/
const lengthOfLongestSubstring = function (s) {
let set = new Set()
let res = 0
let right = -1
for (let i = 0; i < s.length; i++) {
if (i !== 0) {
set.delete(s.charAt(i - 1))
}
// right初值为-1所以判断条件需要注意
while (right < s.length - 1 && !set.has(s.charAt(right + 1))) {
set.add(s.charAt(right + 1))
right++
}
res = Math.max(res, right - i + 1)
}
return res
};
/**
* 解法3:采用map集合滑动窗口
* @param s
* @return {number}
*/
const lengthOfLongestSubstring = (s) => {
let left = 0;
let long = 0;
const map = new Map(), len = s.length;
for (let right = 0; right < len; right++) {
// 遇到重复字符时还要判定 该重复字符的上一次出现位置是否在 滑动窗口左边界 left 的右边
if (map.has(s[right]) && map.get(s[right]) >= left) {
left = map.get(s[right]) + 1; // 都满足,则更新,更新到最近出现的那个重复字符,它的上一个索引的右边
}
long = Math.max(long, right - left + 1); // 比较滑动窗口大小与 long 的长度
map.set(s[right], right); // 无论有没有重复,每次遍历都要更新字符的出现位置
}
return long;
}
lengthOfLongestSubstring("bbbbb")
LeetCode链接
方法1:直接模拟
依照题目给的要求进行模拟
/**
* 自己写的一坨屎山代码,主要还是得多学习内置api
* @param {string} sentence
* @return {string}
*/
const toGoatLatin = function (sentence) {
// sentence = sentence.toLowerCase()
let o = ['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U']
let res = []
let arr = sentence.split(' ')
for (let i = 0; i < arr.length; i++) {
if (o.includes(arr[i][0])) {
let str = arr[i].concat('ma')
for (let j = 0; j < i + 1; j++) {
str = str.concat('a')
}
res.push(str)
} else {
let str = ''
for (let j = 0; j < arr[i].length; j++) {
if (j === arr[i].length - 1) {
str += arr[i][0]
} else {
str += arr[i][j + 1]
}
}
str = str.concat('ma')
for (let j = 0; j < i + 1; j++) {
str = str.concat('a')
}
res.push(str)
}
}
res = res.join(' ')
return res
};
/**
* 看的别人的题解
* @param s
* @return {number}
*/
const toGoatLatin = function (sentence) {
const char = ['a','e','i','o','u']
let res = []
let arr = sentence.split(' ')
for (var i = 0; i < arr.length; i++) {
if (char.includes(arr[i][0].toLowerCase())){
res[i] = arr[i] + 'ma' + 'a'.repeat(i+1)
}else {
res[i] = arr[i].substring(1) + arr[i].charAt(0) + 'ma' +'a'.repeat(i+1)
}
}
return res.join(' ')
};
LeetCode链接
/**
* 解法1:迭代方式实现
* @param {TreeNode} root
* @param {TreeNode} p
* @param {TreeNode} q
* @return {TreeNode}
*/
const lowestCommonAncestor = function (root, p, q) {
while (root) {
if (p.val < root.val && q.val < root.val) {
root = root.left
} else if (q.val > root.val && p.val > root.val) {
root = root.right
} else {
break
}
}
return root
};
/**
* 解法2:递归实现
* @param root
* @param p
* @param q
* @return {*}
*/
const lowestCommonAncestor = function (root, p, q) {
if (root.val>p.val&&root.val>q.val) {
return lowestCommonAncestor(root.left,p,q)
} else if (root.val<p.val&&root.val<q.val){
return lowestCommonAncestor(root.right,p,q)
}
return root
};
LeetCode链接
二叉树的后序遍历,用到了递归。只是那个晚上和吴浪讨论了一下,把代码复现了一遍,还需要继续自己理解以下,再看看
其他的一些题解。
/**
* @param {TreeNode} root
* @param {TreeNode} p
* @param {TreeNode} q
* @return {TreeNode}
*/
var lowestCommonAncestor = function(root, p, q) {
if(root===p||root===q||root===null) return root
let left = lowestCommonAncestor(root.left,p,q)
let right = lowestCommonAncestor(root.right,p,q)
if(left!==null&&right!==null) {
return root
}
if(left!==null&&right===null) {
return left
}else if(left===null&&right!==null) {
return right
}else {
return null
}
};
LeetCode链接
####方法:寻找规律进行迭代
数组nums的和为sumNums,可以模拟一下,F(n-1)与F(n) 之间的关系,发现两者之间相差的数值,这个需要用笔算一下。
F [ 0 ] = 0 × n u m s [ 0 ] + 1 × n u m s [ 1 ] + . . . + ( n − 1 ) × n u m s [ n − 1 ] F [ 1 ] = 1 × n u m s [ 0 ] + 2 × n u m s [ 1 ] + . . . + ( 0 ) × n u m s [ n − 1 ] = F [ 0 ] + n u m S u m − n × n u m s [ n − 1 ] F\left[ 0 \right] \,\,=\,\,0\times nums\left[ 0 \right] \,\,+\,\,1\times nums\left[ 1 \right] \,\,+\,\,... +\left( n-1 \right) \,\,\times \,\,nums\left[ n-1 \right] \\ F\left[ 1 \right] \,\,=\,\,1\times nums\left[ 0 \right] \,\,+\,\,2\times nums\left[ 1 \right] \,\,+\,\,... +\left( 0 \right) \,\,\times \,\,nums\left[ n-1 \right] \,\, \\ =\,\,F\left[ 0 \right] \,\,+\,\,numSum\,\,-\,\,n\times nums\left[ n-1 \right] F[0]=0×nums[0]+1×nums[1]+...+(n−1)×nums[n−1]F[1]=1×nums[0]+2×nums[1]+...+(0)×nums[n−1]=F[0]+numSum−n×nums[n−1]
/**
* 暴力解法失败了!
* @param {number[]} nums
* @return {number}
*/
const maxRotateFunction = function(nums) {
let maxVal = -Infinity
for (let i = 0; i < nums.length-1; i++) {
let sum = 0
nums.unshift(nums.pop())
for (let j = 0; j < nums.length; j++) {
sum+= arr[j]*j
}
maxVal = Math.max(maxVal,sum)
}
return maxVal
};
/**
* 寻找迭代关系
*/
const maxRotateFunction = (nums) => {
let f = 0
// 求原始nums数值的数值和
let numSum = nums.reduce((pre,cur) => {
return pre+cur
},0)
// 计算F(0)从而可以迭代出F1的数值
for (let i = 0; i < nums.length; i++) {
f+=nums[i]*i
}
let maxVal = f
for (let i = nums.length-1; i >0; i--) {
// 第一次f为f(0) k从最开始
// f(1) = f(0) + numSum - nums.length * nums[nums.lenth-k]
f += numSum - nums.length * nums[i]
maxVal = Math.max(f,maxVal)
}
return maxVal
}
LeetCode链接
####方法:直接模拟奇偶数的情况
直接暴力模拟简单有效,需要注意的是数组合并后的排序必须指定回调函数,不然数组中存在负数的时候会导致排序出现错误。
const array1 = ['a', 'b', 'c'];
const array2 = ['d', 'e', 'f'];
const array3 = array1.concat(array2,[1,2,3]);
// 浅拷贝数组
const array4 = arr1.concat()
console.log(array3);
console.log(array4);
if (!nums2.length&&!nums1.length) return 0
let mergeArr = [...nums1,...nums2]
// 指定回调函数,保证排序的准确性
mergeArr.sort((a,b) => {
return a-b
})
if (mergeArr.length&2!==0) {
return mergeArr[Math.floor(mergeArr.length/2)]
}else {
let num1 = mergeArr[Math.floor(mergeArr.length/2)]
let num2 = mergeArr[Math.floor(mergeArr.length/2)-1]
return (num1+num2)/2
}
LeetCode链接
双指针左右搜索遍历,遇到相同的就指针++,代码中写出思路
/**
* @param {string} s
* @return {string}
*/
var longestPalindrome = function(s) {
// 存放最长子串的长度
let max = 0
// 用于更新最长子串的变量
// let str = ''
let masStr = ''
for(let i =0;i<s.length;i++) {
//从当前字符开始计算最长子串的长度
let str = s[i]
// 定义个左指针,右指针不定义呢,得先把和当前字符相等的所有数值都找出来,并获得最后一个相等值的索引
let left = i - 1
while(s[i+1]===s[i]){
str += s[i]
i++
}
// 说明和s[i]相等的值找完了,定义右指针
let right = i + 1
// 向两侧扩展
while(s[left]!==undefined&&s[left] ===s[right]) {
str = s[left] + str + s[right]
left--
right++
}
if(str.length>max) {
max = str.length
maxStr = str
}
}
return maxStr
};
LeetCode链接
题目的底层可以用动态规划来实现,可以将p转为正则表达式,用p匹配s,假如可以匹配,就需要看匹配的结果是否等于,s假如p能 匹配出s则返回true,否则返回false。
/**
* 这题目本来是要用动态规划,实现一个正则表达式的匹配,有点难,学动态规划还是得从简单的学起来,所以这个题目就这么糊弄了
* @param {string} s
* @param {string} p
* @return {boolean}
*/
const isMatch = function (s, p) {
// ${p}是为了操作变量
/**
* let a = 'u'
* 打算匹配变量a中的字符u要这么写的话匹配的是a无法访问变量/a/g
* 写成/${p}/
*/
// eval将字符串转为js表达式
let reg = eval(`/${p}/g`) // 转换成正则表达式
let result = '' //存储匹配到的结果
if (reg.test(s)) {
result = reg[Symbol.match](s)[0]
// 边界条件
if (s.length >= 1 && s.length <= 20 && p.length >= 1 && p.length <= 30) {
// 可以完全匹配字符串s返回
if (s == result) {
return true
} else {
// 匹配的结果不一样返回false
return false
}
}
} else {
// 根本就没匹配到s直接返回就可以
return false
}
};
LeetCode链接
定义一个数组,存放每一行的字符串,遍历原来字符串的时候答案就拼接进去。
/**
* @param {string} s
* @param {number} numRows
* @return {string}
*/
const convert = function (s, numRows) {
if (numRows === 1) return s
// 定义初始数组
let arr = new Array(numRows).fill('')
for (let i = 0, down = true, row = 0; i < s.length; i++) {
// 拼接字符串
arr[row] += s[i]
if (down) {
// 在向下走,行数++
row++
} else {
// 在向上走,行数--
row--
}
// 边界条件
if (row === numRows - 1) {
down = false
} else if (row === 0) {
down = true
}
}
// 数组拼接成字符串返回
return arr.join('')
};
LeetCode链接
看代码
/**
* @param {number} x
* @return {boolean}
*/
const isPalindrome = function(x) {
let s = x +''
// 这句代码跟题目没有关系,只是测一下Array.from()方法,里边可以放迭代器对象,然后就会生成数组。
// 知识点+1
let arr = Array.from(s)
let left=0,right = s.length-1;
for (let i = 0; i <s.length/2; i++) {
// 这里也可以写成这样,不过还是定义双指针思路清晰一些。
if (s[left]!==s[s.length-1-left]) {
return false
}
// if (s[left]!==s[right]) {
// return false
// }
left++
// right--
}
return true
};