function revese (x) {
let rev = 0
while (x !== 0) {
console.log(x)
if (rev < Number.MIN_VALUE / 10 || rev > Number.MAX_VALUE / 10) {
return 0
}
let digit = x % 10
x = Math.floor(x / 10)
rev = rev * 10 + digit
}
return rev
}
字符串反转
var reverseString = function(s) {
const n = s.length;
for (let left = 0, right = n - 1; left < right; ++left, --right) {
[s[left], s[right]] = [s[right], s[left]];
}
};
两数只和等于target
function total(nums, target) {
let map = new Map()
map.set(nums[0], 0)
for (let i = 1; i < nums.length; i++) {
let x = target - nums[i]
if (map.has(x)) {
return [i, map.get(x)]
}
map.set(nums[i], i)
}
}
两数只和等于target,给定的是有序数组
// 双指针
function twoSum (numbers, target) {
let left = 0;
let right = numbers.length - 1
while (left < right) {
if (numbers[left] + numbers[right] === target) {
return [left, right]
}
if (numbers[left] + numbers[right] < target) {
left++
} else {
right--
}
}
return [-1, -1]
}
罗马数字转换
function change (s) {
let sum = 0;
let i;
for (i = 0; i < s.length - 1; i++) {
sum += getValue(s[i + 1]) > getValue(s[i]) ? -getValue(s[i]) : getValue(s[i])
}
// 处理最后一个字符
sum += getValue(s[i])
return sum
}
console.log(change('IV'))
最长公共前缀
// 纵向扫描法
function longestCommonPrefix(strs) {
if (strs == null || strs.length == 0) {
return ''
}
for (let i = 0; i < strs[0].length; i++) {
let c = strs[0][i]
for (let j = 1; j < strs.length; j++) {
console.log(strs[j][i], c)
if (i === strs[j].length || strs[j][i] !== c) {
return strs[0].substring(0, i)
}
}
}
return strs[0]
}
// 二分查找
function longestCommonPrefix(strs) {
if (strs == null || strs.length == 0) {
return ''
}
let minLength = Number.MAX_VALUE
for (let i = 0; i < strs.length; i++) {
minLength = Math.min(minLength, strs[i].length)
}
let low = 0;
let high = minLength
while (low < high) {
let mid = (high + low) >> 1
if (isCommonPrefix(strs, mid)) {
low = mid + 1
} else {
high = mid - 1
}
}
return strs[0].substring(0, low)
}
function isCommonPrefix(strs, length) {
let str0 = strs[0].substring(0, length)
let count = strs.length
for (let i = 1; i < count; i++) {
let str = strs[i]
for (let j = 0; j < length; j++) {
if (str0[j] !== str[j]) {
return false
}
}
}
return true
}
console.log(longestCommonPrefix(['12121212', '12', '1234']))
删除数组中重复的项目
// 双指针
function removeDuplicates( nums) {
let n = nums.length
if (n === 0) {
return 0
}
let fast = 1
let slow = 1
while (fast < n) {
if (nums[fast] !== nums[fast - 1]) {
nums[slow] = nums[fast]
++slow
}
++fast
}
return slow
}
移除元素,删除数组中指定的重复元素
var removeElement = function(nums, val) {
let left = 0, right = nums.length;
while (left < right) {
if (nums[left] === val) {
nums[left] = nums[right - 1];
right--;
} else {
left++;
}
}
return left;
};
搜索插入位置
function insert (arr, num) {
let left = 0
let right = arr.length - 1
let ans = right
while (left < right) {
let mid = (left + right) >> 1
let target = arr[mid]
if (target >= num) {
ans = mid
right = mid - 1
} else {
left = mid + 1
}
}
console.log(ans)
}
二叉树的中序遍历
var inorderTraversal = function(root) {
const res = [];
const inorder = (root) => {
if (!root) {
return;
}
inorder(root.left);
res.push(root.val);
inorder(root.right);
}
inorder(root);
return res;
};
合并已排序的数组
function mergeArray(first, sec) {
var temp = []
var t = 0
var i = 0
var j = 0
var k
// 取较短的数组开始loop
var mid = (first.length <= sec.length) ? first.length - 1 : sec.length - 1
while (i <= mid && j <= mid) {
//关键的逻辑在于这行
k = (first[i] < sec[j]) ? first[i++] : sec[j++]
//过滤重复元素
if (t > 0 && k == temp[t - 1]) {
continue
}
temp[t++] = k
}
// 将first数组中剩余的元素追加到temp
while (i <= first.length - 1) {
k = first[i++]
if (t > 0 && k == temp[t - 1]) continue
temp[t++] = k
}
// 将sec数组中剩余的元素追加到temp
while (j <= sec.length - 1) {
k = sec[j++]
if (t > 0 && k == temp[t - 1]) continue
temp[t++] = k
}
return temp
}
console.log(mergeArray([1, 2, 3], [2, 3, 4, 6]))
合并二叉树
function mergeTrees(t1, t2) {
if (t1 == null)
return t2;
if (t2 == null)
return t1;
t1.value += t2.value;
let left = mergeTrees(t1.left, t2.left);
if (left) {
t1.left = left
}
let right = mergeTrees(t1.right, t2.right);
if (right) {
t1.right = right
}
return t1;
}
console.log(mergeTrees(rootA, rootB))
function reverse(node) {
if (node != null) {
let temp = node.left;
node.left = node.right;
node.right = temp;
reverse(node.left);
reverse(node.right);
}
}
二叉树的最大深度
function maxDepth (root) {
if (root === null) {
return 0
}
return 1 + Math.max(maxDepth(root.left), maxDepth(root.right))
}
二叉树的最小深度
function minDepth (root) {
if (root === null) {
return 0
}
return 1 + Math.min(minDepth(root.left), minDepth(root.right))
}
将有序数组转换为二叉树
// 尽量构建一个平衡二叉树,使元素均匀分布
function solution(nums) {
function TreeNode(value) {
this.value = value
this.left = null
this.right = null
}
function arrayToBST(nums, start, end) {
if (end < start) {
return null
}
let mid = (start + end) >> 1
let root = new TreeNode(nums[mid])
root.left = arrayToBST(nums, start, mid - 1)
root.right = arrayToBST(nums, mid + 1, end)
return root
}
return arrayToBST(nums, 0, nums.length - 1)
}
console.log(solution([-10, -3, 0, 5, 9]))
路径总和
function hasPathSum (root, sum) {
if (root === null) {
return false
}
let node = [root]
let value = [root.value]
while (node.length) {
let now = node.pop()
let temp = value.pop()
if (temp === sum) {
return true
}
if (now.left && now.left !== null) {
node.push(now.left)
value.push(now.left.value + temp)
}
if (now.right && now.right !== null) {
node.push(now.right)
value.push(now.right.value + temp)
}
}
return false
}
计算买卖股票的最佳时机
function maxProfix (prices) {
if (!prices) {
return 0
}
let min_price = Number.MAX_VALUE // 记录最小的股值
let max_profit = 0; // 最大的利润
for (let i = 0; i < prices.length; i++) {
let p = prices[i]
if (p < min_price) {
// 当前股值小于最小股值时,记录到最小股值里面
min_price = p
}
if (p - min_price > max_profit) {
// 当前利润大于最大利润时,记录到最大利润值里面
max_profit = p - min_price
}
}
return max_profit
}
let arr = [7, 1, 5, 3, 6, 4]
console.log(maxProfix(arr))
判断回文字符串
// 双指针
function isPaindrome(s) {
if (!s) {
return true
}
let left = 0
let right = s.length - 1
while (left < right) {
if (s[left] !== s[right]) {
return false
}
left++
right--
}
return true
}
console.log(isPaindrome('abba'))
只出现一次的数字
function singleNumber (nums) {
// 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次
let set = new Set()
for (let i = 0; i < nums.length; i++) {
let current = nums[i]
if (set.has(current)) {
set.delete(current)
} else {
set.add(current)
}
}
console.log(set)
}
console.log(singleNumber([1, 2, 2, 3, 3]))
二叉树先序遍历
function preorderTrvaersal (root) {
function preorder (root, res) {
if (root === null) {
return
}
res.push(root.value)
preorder(root.left, res)
preorder(root.right, res)
}
let res = []
preorder(root, res)
return res
}
二叉树后续遍历
function postorderTrvaersal (root) {
function postorder (root, res) {
if (root === null) {
return
}
postorder(root.left, res)
postorder(root.right, res)
res.push(root.value)
}
let res = []
postorder(root, res)
return res
}
阶乘后的零
function trailingZeroes (n) {
// 先计算阶乘
function sum (num) {
if (num <= 1) {
return 1
} else {
return num * sum(num - 1)
}
}
// 再计算零
let count = sum(n)
let zero_count = 0
while (count % 10 === 0) {
zero_count += 1
count /= 10
}
return zero_count
}
console.log(trailingZeroes(5))
计数质数
质数的定义:在大于 11 的自然数中,除了 11 和它本身以外不再有其他因数的自然数
const isPrime = x => {
for (let i = 2; i * i <= x; i++) {
if (x % i === 0) {
return false
}
}
return true
}
function countPrimes (n) {
let ans = 0
for (let i = 2; i < n; i++) {
ans += isPrime(i)
}
return ans
}
丑数
若 n 是丑数,则 n 可以写成 n = 2^a 3^b 5^c
var isUgly = function(n) {
if (n <= 0) {
return false;
}
const factors = [2, 3, 5];
for (const factor of factors) {
while (n % factor === 0) {
n /= factor;
}
}
return n == 1;
};
存在重复元素
var containsDuplicate = function(nums) {
const set = new Set();
for (const x of nums) {
if (set.has(x)) {
return true;
}
set.add(x);
}
return false;
};
// 队列 shift首部删除 unshift 首部添加
// 栈 push 添加, pop 删除
class MyStack {
constructor () {
this.queue1 = []
this.queue2 = []
}
push (x) {
this.queue2.push(x)
while (this.queue1.length) {
this.queue2.push(this.queue1.shift())
}
let temp = this.queue1
this.queue1 = this.queue2
this.queue2 = temp
}
pop () {
return this.queue1.shift()
}
}
const stack = new MyStack()
stack.push(88)
stack.push(99)
console.log(stack.pop())
console.log(stack.queue1)
进制转换
function mulBase(num, base) {
var s = [];
do {
s.push(num % base);
num = Math.floor(num /= base);
} while (num > 0);
var converted = "";
while (s.length > 0) {
converted += s.pop();
}
return converted;
}
实现栈
function Stack() {
this.dataStore = [];
this.top = 0;
this.push = push;
this.pop = pop;
this.peek = peek;
this.clear = clear;
}
function push(element) {
this.dataStore[this.top++] = element;
}
function pop() {
return this.dataStore[--this.top];
}
function peek() {
return this.dataStore[this.top - 1];
}
function length() {
return this.top;
}
function clear() {
this.top = 0;
}
let stack = new Stack()
stack.push(1)
stack.push(2)
stack.clear()
汇总区间
function summaryRanges (nums) {
let ret = []
let i = 0
let n = nums.length;
while (i < n) {
let low = i;
i++
while (i < n && nums[i] === nums[i - 1] + 1) {
i++
}
let high = i - 1;
let temp = ['' + nums[low]]
// 每次遇到相邻元素之间的差值大于 11 时
if (low < high) {
temp.push('->')
temp.push('' + nums[high])
}
ret.push(temp.join(''))
}
return ret
}
console.log(summaryRanges([1,2,3, 6,7,8]))
2的幂
var isPowerOfTwo = function(n) {
return n > 0 && (n & (n - 1)) === 0;
};
二叉搜索树的最近公共祖先
//p 和 q 的最近公共祖先就是从根节点到它们路径上的「分岔点」
function lowestCommon (root, p, q) {
let ancestor = root
while (true) {
if (p.value < ancestor.value && q.value < ancestor.value && ancestor.left) {
// 如果当前节点的值大于 p 和 q 的值,说明 p 和 q 应该在当前节点的左子树,因此将当前节点移动到它的左子节点;
ancestor = ancestor.left
} else if (p.value > ancestor.value && q.value > ancestor.value && ancestor.right) {
// 如果当前节点的值小于 p 和 q 的值,说明 p 和 q 应该在当前节点的右子树,因此将当前节点移动到它的右子节点;
ancestor = ancestor.right
} else {
break
}
}
return ancestor
}
有效的字母异位词
t 是 ss 的异位词等价于「两个字符串排序后相等」。因此我们可以对字符串 ss 和 tt 分别排序,看排序后的字符串是否相等即可判断
function missingNumber (nums) {
// [0, 1, 2]
nums.sort((a, b) => a - b)
// 判断n出现在末位
if (nums[nums.length - 1] !== nums.length) {
return nums.length
}
// 判断0出现在首位
if (nums[0] !== 0) {
return 0
}
for (let i = 1; i < nums.length; i++) {
let expectedNum = nums[i - 1] + 1
if (nums[i] !== expectedNum) {
return expectedNum
}
}
return -1
}
移动零
function mmoveZeroes(nums) {
let n = nums.length
let left = 0
let right = 0
while (right < n) {
if (nums[right]) {
swap(nums, left, right)
left++
}
right++
}
}
function swap(arr, a, b) {
if (a === b) {
return
}
let temp = arr[a]
arr[a] = arr[b]
arr[b] = temp
}
let arr = [1, 2, 3]
mmoveZeroes(arr)
console.log(arr)
3 的幂
找出数字 n 是否是数字 b 的幂的一个简单方法是,n%3 只要余数为 0,就一直将 n 除以 b。
function isPowerOfThree(n) {
if (n < 1) {
return false;
}
while (n % 3 == 0) {
n /= 3;
}
return n == 1;
}
完全平方根
function isPerfectSquare (num) {
if (num < 2) {
return true
}
let left = 2
let right = num / 2
let guessSquared;
while (left <= right) {
x = (left + right) >> 1
guessSquared = x * x;
if (guessSquared === num) {
return true
}
if (guessSquared > num) {
right = x - 1
} else {
left = x + 1
}
}
return false
}
中序遍历,二叉树最小绝对值差
function getMin (root) {
let ans = Number.MAX_VALUE
let pre = -1;
const dfs = (root) => {
if (root === null) {
return
}
dfs(root.left)
if (pre === -1) {
pre = root.value
} else {
ans = Math.min(ans, root.value - pre)
pre = root.value
}
dfs(root.root)
}
dfs(root)
return ans;
}
判断一颗树是另一颗树的子树
function isSubtree(s, t) {
function dfs (s, t) {
if (s === null) {
return false
}
return check(s, t) || dfs(s.left, t) || dfs(s.right, t)
}
function check (s, t) {
if (s === null && t === null) {
return true
}
if (s === null || t === null || s.value !== t.value) {
return false
}
return check(s.left, t.left) && check(s.right, t.right)
}
return dfs(s, t)
}
function pivotIndex (nums) {
const total = nums.reduces((a, b) => a + b, 0)
let sum = 0;
for (let i = 0; i < nums.length; i++) {
if (2 * sum + nums[i] === total) {
return i
}
sum += nums[i]
}
return -1
}
前位分割数
var thousandSeparator = function(n) {
let count = 0;
let ans = "";
do {
let cur = n % 10;
n = Math.floor(n / 10);
ans += cur.toString();
++count;
if (count % 3 == 0 && n) {
ans += '.';
}
} while (n);
return ans.split('').reverse().join('');
};
深度克隆
function deepClone (obj, hash = new WeakMap()) {
if (obj == null) return obj;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
if (typeof obj === 'symbol') {
let desc = obj.description
return desc ? Symbol(desc) : Symbol()
}
if (typeof obj !== 'object') return obj;
if (hash.has(obj)) return hash.get(obj);
let cloneObj = new obj.constructor;
hash.set(obj, cloneObj);
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
cloneObj[key] = deepClone(obj[key]);
}
}
return cloneObj;
}
整数反转
字符串反转
两数只和等于target
两数只和等于target,给定的是有序数组
罗马数字转换
最长公共前缀
删除数组中重复的项目
移除元素,删除数组中指定的重复元素
搜索插入位置
二叉树的中序遍历
合并已排序的数组
合并二叉树
判断对称二叉树
二叉树翻转
二叉树的最大深度
二叉树的最小深度
将有序数组转换为二叉树
路径总和
计算买卖股票的最佳时机
判断回文字符串
只出现一次的数字
二叉树先序遍历
二叉树后续遍历
阶乘后的零
计数质数 质数的定义:在大于 11 的自然数中,除了 11 和它本身以外不再有其他因数的自然数
丑数 若 n 是丑数,则 n 可以写成 n = 2^a 3^b 5^c
存在重复元素
用队列实现栈 栈是一种后进先出的数据结构,元素从顶端入栈,然后从顶端出栈。 队列是一种先进先出的数据结构,元素从后端入队,然后从前端出队。
进制转换
实现栈
汇总区间
2的幂
二叉搜索树的最近公共祖先
有效的字母异位词 t 是 ss 的异位词等价于「两个字符串排序后相等」。因此我们可以对字符串 ss 和 tt 分别排序,看排序后的字符串是否相等即可判断
二叉树的所有路径
各位相加
缺失数字
移动零
3 的幂 找出数字 n 是否是数字 b 的幂的一个简单方法是,n%3 只要余数为 0,就一直将 n 除以 b。
完全平方根
中序遍历,二叉树最小绝对值差
判断一颗树是另一颗树的子树
根据二叉树创建字符串
寻找数组中的中心索引
前位分割数
深度克隆
调度器
模版字符串