1. 通过快慢指针寻找链表中点
function findCenter ( head ) {
let slower = head, faster = head;
while ( faster && faster. next != null ) {
slower = slower. next;
faster = faster. next. next;
}
if ( faster != null ) {
slower = slower. next;
}
return slower;
}
2. 前序遍历判断回文链表
var isPalindrome = function ( head ) {
let left = head;
function traverse ( right ) {
if ( right == null ) return true ;
let res = traverse ( right. next) ;
res = res && ( right. val === left. val) ;
left = left. next;
return res;
}
return traverse ( head) ;
} ;
3.反转链表
var reverseList = function ( head ) {
if ( head == null || head. next == null ) return head;
let last = reverseList ( head. next) ;
head. next. next = head;
head. next = null ;
return last;
} ;
4. 合并K个升序链表(困难)
var mergeKLists = function ( lists ) {
if ( lists. length === 0 ) return null ;
return mergeArr ( lists) ;
} ;
function mergeArr ( lists ) {
if ( lists. length <= 1 ) return lists[ 0 ] ;
let index = Math. floor ( lists. length / 2 ) ;
const left = mergeArr ( lists. slice ( 0 , index) )
const right = mergeArr ( lists. slice ( index) ) ;
return merge ( left, right) ;
}
function merge ( l1, l2 ) {
if ( l1 == null && l2 == null ) return null ;
if ( l1 != null && l2 == null ) return l1;
if ( l1 == null && l2 != null ) return l2;
let newHead = null , head = null ;
while ( l1 != null && l2 != null ) {
if ( l1. val < l2. val) {
if ( ! head) {
newHead = l1;
head = l1;
} else {
newHead. next = l1;
newHead = newHead. next;
}
l1 = l1. next;
} else {
if ( ! head) {
newHead = l2;
head = l2;
} else {
newHead. next = l2;
newHead = newHead. next;
}
l2 = l2. next;
}
}
newHead. next = l1 ? l1 : l2;
return head;
}
5. K 个一组翻转链表(困难)
var reverseKGroup = function ( head, k ) {
let a = head, b = head;
for ( let i = 0 ; i < k; i++ ) {
if ( b == null ) return head;
b = b. next;
}
const newHead = reverse ( a, b) ;
a. next = reverseKGroup ( b, k) ;
return newHead;
} ;
function reverse ( a, b ) {
let prev = null , cur = a, nxt = a;
while ( cur != b) {
nxt = cur. next;
cur. next = prev;
prev = cur;
cur = nxt;
}
return prev;
}
5. 环形链表(简单)
var hasCycle = function ( head ) {
if ( head == null || head. next == null ) return false ;
let slower = head, faster = head;
while ( faster != null && faster. next != null ) {
slower = slower. next;
faster = faster. next. next;
if ( slower === faster) return true ;
}
return false ;
} ;
6. 排序链表(中等)
var sortList = function ( head ) {
if ( head == null ) return null ;
let newHead = head;
return mergeSort ( head) ;
} ;
function mergeSort ( head ) {
if ( head. next != null ) {
let slower = getCenter ( head) ;
let nxt = slower. next;
slower. next = null ;
console. log ( head, slower, nxt) ;
const left = mergeSort ( head) ;
const right = mergeSort ( nxt) ;
head = merge ( left, right) ;
}
return head;
}
function merge ( left, right ) {
let newHead = null , head = null ;
while ( left != null && right != null ) {
if ( left. val < right. val) {
if ( ! head) {
newHead = left;
head = left;
} else {
newHead. next = left;
newHead = newHead. next;
}
left = left. next;
} else {
if ( ! head) {
newHead = right;
head = right;
} else {
newHead. next = right;
newHead = newHead. next;
}
right = right. next;
}
}
newHead. next = left ? left : right;
return head;
}
function getCenter ( head ) {
let slower = head, faster = head. next;
while ( faster != null && faster. next != null ) {
slower = slower. next;
faster = faster. next. next;
}
return slower;
}
7. 相交链表(简单)
var getIntersectionNode = function ( headA, headB ) {
let lastHeadA = null ;
let lastHeadB = null ;
let originHeadA = headA;
let originHeadB = headB;
if ( ! headA || ! headB) {
return null ;
}
while ( true ) {
if ( headB == headA) {
return headB;
}
if ( headA && headA. next == null ) {
lastHeadA = headA;
headA = originHeadB;
} else {
headA = headA. next;
}
if ( headB && headB. next == null ) {
lastHeadB = headB
headB = originHeadA;
} else {
headB = headB. next;
}
if ( lastHeadA && lastHeadB && lastHeadA != lastHeadB) {
return null ;
}
}
return null ;
} ;
8. 最长回文子串(中等)
var longestPalindrome = function ( s ) {
if ( s. length === 1 ) return s;
let maxRes = 0 , maxStr = '' ;
for ( let i = 0 ; i < s. length; i++ ) {
let str1 = palindrome ( s, i, i) ;
let str2 = palindrome ( s, i, i + 1 ) ;
if ( str1. length > maxRes) {
maxStr = str1;
maxRes = str1. length;
}
if ( str2. length > maxRes) {
maxStr = str2;
maxRes = str2. length;
}
}
return maxStr;
} ;
function palindrome ( s, l, r ) {
while ( l >= 0 && r < s. length && s[ l] === s[ r] ) {
l-- ;
r++ ;
}
return s. slice ( l + 1 , r) ;
}
9. 最长公共前缀(简单)
var longestCommonPrefix = function ( strs ) {
if ( strs. length === 0 ) return "" ;
let first = strs[ 0 ] ;
if ( first === "" ) return "" ;
let minLen = Number. MAX_SAFE_INTEGER ;
for ( let i = 1 ; i < strs. length; i++ ) {
const len = twoStrLongestCommonPrefix ( first, strs[ i] ) ;
minLen = Math. min ( len, minLen) ;
}
return first. slice ( 0 , minLen) ;
} ;
function twoStrLongestCommonPrefix ( s, t ) {
let i = 0 , j = 0 ;
let cnt = 0 ;
while ( i < s. length && j < t. length) {
console. log ( s[ i] , t[ j] , cnt)
if ( s[ i] === t[ j] ) {
cnt++ ;
} else {
return cnt;
}
i++ ;
j++ ;
}
return cnt;
}
10. 无重复字符的最长子串(中等))
var lengthOfLongestSubstring = function ( s ) {
let window = { } ;
let left = 0 , right = 0 ;
let maxLen = 0 , maxStr = '' ;
while ( right < s. length) {
let c = s[ right] ;
right++ ;
if ( window[ c] ) window[ c] ++ ;
else window[ c] = 1
while ( window[ c] > 1 ) {
let d = s[ left] ;
left++ ;
window[ d] -- ;
}
if ( maxLen < right - left) {
maxLen = right - left;
}
}
return maxLen;
} ;
11. 最小覆盖子串(困难)
var minWindow = function ( s, t ) {
let need = { } , window = { } ;
for ( let c of t) {
if ( ! need[ c] ) need[ c] = 1 ;
else need[ c] ++ ;
}
let left = 0 , right = 0 ;
let valid = 0 , len = Object. keys ( need) . length;
let minLen = s. length + 1 , minStr = '' ;
while ( right < s. length) {
const d = s[ right] ;
right++ ;
if ( ! window[ d] ) window[ d] = 1 ;
else window[ d] ++ ;
if ( need[ d] && need[ d] === window[ d] ) {
valid++ ;
}
console. log ( 'left - right' , left, right) ;
while ( valid === len) {
if ( right - left < minLen) {
minLen = right - left;
minStr = s. slice ( left, right) ;
}
console. lo
let c = s[ left] ;
left++ ;
window[ c] -- ;
if ( need[ c] && window[ c] < need[ c] ) {
valid-- ;
}
}
}
return minStr;
} ;
12. 俄罗斯套娃信封问题(困难)
var maxEnvelopes = function ( envelopes ) {
if ( envelopes. length === 1 ) return 1 ;
envelopes. sort ( ( a, b ) => {
if ( a[ 0 ] !== b[ 0 ] ) return a[ 0 ] - b[ 0 ] ;
else return b[ 1 ] - a[ 1 ] ;
} ) ;
let LISArr = [ ] ;
for ( let [ key, value] of envelopes) {
LISArr. push ( value) ;
}
console. log ( LISArr) ;
return LIS ( LISArr) ;
} ;
function LIS ( arr ) {
let dp = [ ] ;
let maxAns = 0 ;
for ( let i = 0 ; i < arr. length; i++ ) {
dp[ i] = 1 ;
}
for ( let i = 1 ; i < arr. length; i++ ) {
for ( let j = i; j >= 0 ; j-- ) {
if ( arr[ i] > arr[ j] ) {
dp[ i] = Math. max ( dp[ i] , dp[ j] + 1 )
}
maxAns = Math. max ( maxAns, dp[ i] ) ;
}
}
return maxAns;
}
13. 最长连续递增序列(简单)
var findLengthOfLCIS = function ( nums ) {
if ( nums. length === 0 ) return 0 ;
const n = nums. length;
let left = 0 , right = 1 ;
let globalMaxLen = 1 , maxLen = 1 ;
while ( right < n) {
if ( nums[ right] > nums[ left] ) maxLen++ ;
else {
maxLen = 1 ;
}
left++ ;
right++ ;
globalMaxLen = Math. max ( globalMaxLen, maxLen) ;
}
return globalMaxLen;
} ;
14. 最长连续序列(困难)
var longestConsecutive = function ( nums ) {
if ( nums. length === 0 ) return 0 ;
const set = new Set ( nums) ;
const n = nums. length;
let globalLongest = 1 ;
for ( let i = 0 ; i < n; i++ ) {
if ( ! set. has ( nums[ i] - 1 ) ) {
let longest = 1 ;
let currentNum = nums[ i] ;
while ( set. has ( currentNum + 1 ) ) {
currentNum += 1 ;
longest++ ;
}
globalLongest = Math. max ( globalLongest, longest) ;
}
}
return globalLongest;
} ;
15. 盛最多水的容器(中等)
var maxArea = function ( height ) {
let n = height. length;
let left = 0 , right = n - 1 ;
let maxOpacity = 0 ;
while ( left < right) {
let res = Math. min ( height[ left] , height[ right] ) * ( right - left) ;
maxOpacity = Math. max ( maxOpacity, res) ;
if ( height[ left] < height[ right] ) left++
else right-- ;
}
return maxOpacity;
} ;
16. 寻找两个正序数组的中位数(困难)
var findMedianSortedArrays = function ( nums1, nums2 ) {
let m = nums1. length, n = nums2. length;
let i = 0 , j = 0 ;
let newArr = [ ] ;
while ( i < m && j < n) {
if ( nums1[ i] < nums2[ j] ) {
newArr. push ( nums1[ i++ ] ) ;
} else {
newArr. push ( nums2[ j++ ] ) ;
}
}
newArr = newArr. concat ( i < m ? nums1. slice ( i) : nums2. slice ( j) ) ;
const len = newArr. length;
console. log ( newArr)
if ( len % 2 === 0 ) {
return ( newArr[ len / 2 ] + newArr[ len / 2 - 1 ] ) / 2 ;
} else {
return newArr[ Math. floor ( len / 2 ) ] ;
}
} ;
17. 删除有序数组中的重复项(简单)
var removeDuplicates = function ( nums ) {
if ( nums. length <= 1 ) return nums. length;
let lo = 0 , hi = 0 ;
while ( hi < nums. length) {
while ( nums[ lo] === nums[ hi] && hi < nums. length) hi++ ;
if ( nums[ lo] !== nums[ hi] && hi < nums. length) {
lo++ ;
nums[ lo] = nums[ hi] ;
}
hi++ ;
}
return lo + 1 ;
} ;
18. 岛屿的最大面积(中等)
let maxX, maxY; let visited; let globalMaxArea;
var maxAreaOfIsland = function ( grid ) {
visited = new Set ( ) ;
maxX = grid. length;
maxY = grid[ 0 ] . length;
globalMaxArea = 0 ;
for ( let i = 0 ; i < maxX; i++ ) {
for ( let j = 0 ; j < maxY; j++ ) {
if ( grid[ i] [ j] === 1 ) {
visited. add ( ` ( ${ i} , ${ j} ) ` ) ;
globalMaxArea = Math. max ( globalMaxArea, dfs ( grid, i, j) ) ;
}
visited. clear ( ) ;
}
}
return globalMaxArea;
} ;
function dfs ( grid, x, y ) {
let res = 1 ;
for ( let i = - 1 ; i <= 1 ; i++ ) {
for ( let j = - 1 ; j <= 1 ; j++ ) {
if ( Math. abs ( i) === Math. abs ( j) ) continue ;
const newX = x + i;
const newY = y + j;
if ( newX >= maxX || newX < 0 || newY >= maxY || newY < 0 ) continue ;
if ( visited. has ( ` ( ${ newX} , ${ newY} ) ` ) ) continue ;
visited. add ( ` ( ${ newX} , ${ newY} ) ` ) ;
const areaCnt = grid[ newX] [ newY]
if ( areaCnt === 1 ) {
const cnt = dfs ( grid, newX, newY) ;
res += cnt;
}
}
}
return res;
}
19. 和为K的子数组(中等)
var subarraySum = function ( nums, k ) {
let cnt = 0 ;
let sum0_i = 0 , sum0_j = 0 ;
let map = new Map ( ) ;
map. set ( 0 , 1 ) ;
for ( let i = 0 ; i <= nums. length; i++ ) {
sum0_i += nums[ i] ;
sum0_j = sum0_i - k;
console. log ( 'map' , sum0_j, map. get ( sum0_j) )
if ( map. has ( sum0_j) ) {
cnt += map. get ( sum0_j) ;
}
let sumCnt = map. get ( sum0_i) || 0 ;
map. set ( sum0_i, sumCnt + 1 ) ;
}
return cnt;
} ;
nSum问题【哈希表】【系列】
1. 两数之和(简单)
var twoSum = function ( nums, target ) {
let map2 = new Map ( ) ;
for ( let i = 0 ; i < nums. length; i++ ) {
map2. set ( nums[ i] , i) ;
}
for ( let i = 0 ; i < nums. length; i++ ) {
if ( map2. has ( target - nums[ i] ) && map2. get ( target - nums[ i] ) !== i) return [ i, map2. get ( target - nums[ i] ) ]
}
} ;
2. 接雨水(困难)
var trap = function ( height ) {
let l_max = [ ] , r_max = [ ] ;
let len = height. length;
let maxCapacity = 0 ;
for ( let i = 0 ; i < len; i++ ) {
l_max[ i] = height[ i] ;
r_max[ i] = height[ i] ;
}
for ( let i = 1 ; i < len; i++ ) {
l_max[ i] = Math. max ( l_max[ i - 1 ] , height[ i] ) ;
}
for ( let j = len - 2 ; j >= 0 ; j-- ) {
r_max[ j] = Math. max ( r_max[ j + 1 ] , height[ j] ) ;
}
for ( let i = 0 ; i < len; i++ ) {
maxCapacity += Math. min ( l_max[ i] , r_max[ i] ) - height[ i] ;
}
return maxCapacity;
} ;
跳跃游戏【贪心算法】【系列】
1. 跳跃游戏(中等)
var canJump = function ( nums ) {
let faster = 0 ;
for ( let i = 0 ; i < nums. length - 1 ; i++ ) {
faster = Math. max ( faster, i + nums[ i] ) ;
if ( faster <= i) return false ;
}
return faster >= nums. length - 1 ;
} ;
【二叉树】【系列】
1. 二叉树的最近公共祖先(简单)
let visited; let parent;
var lowestCommonAncestor = function ( root, p, q ) {
visited = new Set ( ) ;
parent = new Map ( ) ;
dfs ( root) ;
while ( p != null ) {
visited. add ( p. val) ;
p = parent. get ( p. val) ;
}
while ( q != null ) {
if ( visited. has ( q. val) ) {
return q;
}
q = parent. get ( q. val) ;
}
return null ;
} ;
function dfs ( root ) {
if ( root. left != null ) {
parent. set ( root. left. val, root) ;
dfs ( root. left) ;
}
if ( root. right != null ) {
parent. set ( root. right. val, root) ;
dfs ( root. right) ;
}
}
2. 二叉搜索树中的搜索(简单)
var searchBST = function ( root, val ) {
if ( root == null ) return null ;
if ( root. val === val) return root;
if ( root. val > val) {
return searchBST ( root. left, val) ;
} else if ( root. val < val) {
return searchBST ( root. right, val) ;
}
} ;
3. 删除二叉搜索树中的节点(中等)
var deleteNode = function ( root, key ) {
if ( root == null ) return null ;
if ( root. val === key) {
if ( root. left == null && root. right == null ) return null ;
if ( root. left == null ) return root. right;
if ( root. right == null ) return root. left;
if ( root. left != null && root. right != null ) {
let target = getMinTreeMaxNode ( root. left) ;
root. val = target. val;
root. left = deleteNode ( root. left, target. val) ;
}
}
if ( root. val < key) {
root. right = deleteNode ( root. right, key) ;
} else if ( root. val > key) {
root. left = deleteNode ( root. left, key) ;
}
return root;
} ;
function getMinTreeMaxNode ( root ) {
if ( root. right == null ) return root;
return getMinTreeMaxNode ( root. right) ;
}
4. 完全二叉树的节点个数(中等)
var countNodes = function ( root ) {
if ( root == null ) return 0 ;
let l = root, r = root;
let lh = 0 , rh = 0 ;
while ( l != null ) {
l = l. left;
lh++ ;
}
while ( r != null ) {
r = r. right;
rh++ ;
}
if ( lh === rh) {
return Math. pow ( 2 , lh) - 1 ;
}
return 1 + countNodes ( root. left) + countNodes ( root. right) ;
} ;
5. 二叉树的锯齿形层序遍历(中等)
let res;
var zigzagLevelOrder = function ( root ) {
if ( root == null ) return [ ] ;
res = [ ] ;
BFS ( root, true ) ;
return res;
} ;
function BFS ( root, inOrder ) {
let arr = [ ] ;
let resItem = [ ] ;
let node;
let stack1 = new Stack ( ) ;
let stack2 = new Stack ( ) ;
let flag;
stack1. push ( root) ;
res. push ( [ root. val] ) ;
inOrder = ! inOrder;
while ( ! stack1. isEmpty ( ) || ! stack2. isEmpty ( ) ) {
if ( stack1. isEmpty ( ) ) {
flag = 'stack1' ;
} else if ( stack2. isEmpty ( ) ) {
flag = 'stack2' ;
}
if ( flag === 'stack2' && ! stack1. isEmpty ( ) ) node = stack1. pop ( ) ;
else if ( flag === 'stack1' && ! stack2. isEmpty ( ) ) node = stack2. pop ( ) ;
if ( inOrder) {
if ( node. left) {
if ( flag === 'stack1' ) {
stack1. push ( node. left) ;
} else {
stack2. push ( node. left) ;
}
resItem. push ( node. left. val) ;
}
if ( node. right) {
if ( flag === 'stack1' ) {
stack1. push ( node. right) ;
} else {
stack2. push ( node. right) ;
}
resItem. push ( node. right. val) ;
}
} else {
if ( node. right) {
if ( flag === 'stack1' ) {
stack1. push ( node. right) ;
} else {
stack2. push ( node. right) ;
}
resItem. push ( node. right. val) ;
}
if ( node. left) {
if ( flag === 'stack1' ) {
stack1. push ( node. left) ;
} else {
stack2. push ( node. left) ;
}
resItem. push ( node. left. val) ;
}
}
if ( ( flag === 'stack2' && stack1. isEmpty ( ) ) || ( flag === 'stack1' && stack2. isEmpty ( ) ) ) {
inOrder = ! inOrder;
if ( resItem. length > 0 ) {
res. push ( resItem) ;
}
resItem = [ ] ;
}
}
}
class Stack {
constructor ( ) {
this . count = 0 ;
this . items = [ ] ;
}
push ( element ) {
this . items[ this . count] = element;
this . count++ ;
}
pop ( ) {
if ( this . isEmpty ( ) ) return undefined ;
const element = this . items[ this . count - 1 ] ;
delete this . items[ this . count - 1 ] ;
this . count-- ;
return element;
}
size ( ) {
return this . count;
}
isEmpty ( ) {
return this . size ( ) === 0 ;
}
}
【排序算法】【系列】
1. 用最少数量的箭引爆气球(中等)
var findMinArrowShots = function ( points ) {
if ( points. length === 0 ) return 0 ;
points. sort ( ( a, b ) => a[ 1 ] - b[ 1 ] ) ;
let cnt = 1 ;
let resArr = [ points[ 0 ] ] ;
let curr, last;
for ( let i = 1 ; i < points. length; i++ ) {
curr = points[ i] ;
last = resArr[ resArr. length - 1 ] ;
if ( curr[ 0 ] > last[ 1 ] ) {
resArr. push ( curr) ;
cnt++ ;
}
}
return cnt;
} ;
2. 合并区间(中等)
var merge = function ( intervals ) {
if ( intervals. length === 0 ) return [ ] ;
intervals. sort ( ( a, b ) => a[ 0 ] - b[ 0 ] ) ;
let mergeArr = [ intervals[ 0 ] ] ;
let last, curr;
for ( let j = 1 ; j < intervals. length; j++ ) {
last = mergeArr[ mergeArr. length - 1 ] ;
curr = intervals[ j] ;
if ( last[ 1 ] >= curr[ 0 ] ) {
last[ 1 ] = Math. max ( curr[ 1 ] , last[ 1 ] ) ;
} else {
mergeArr. push ( curr) ;
}
}
return mergeArr;
} ;
【 二分查找 】
1. 寻找两个正序数组的中位数(困难)
var findMedianSortedArrays = function ( nums1, nums2 ) {
let m = nums1. length, n = nums2. length;
let i = 0 , j = 0 ;
let newArr = [ ] ;
while ( i < m && j < n) {
if ( nums1[ i] < nums2[ j] ) {
newArr. push ( nums1[ i++ ] ) ;
} else {
newArr. push ( nums2[ j++ ] ) ;
}
}
newArr = newArr. concat ( i < m ? nums1. slice ( i) : nums2. slice ( j) ) ;
const len = newArr. length;
console. log ( newArr)
if ( len % 2 === 0 ) {
return ( newArr[ len / 2 ] + newArr[ len / 2 - 1 ] ) / 2 ;
} else {
return newArr[ Math. floor ( len / 2 ) ] ;
}
} ;
2. 判断子序列(简单)
var isSubsequence = function ( s, t ) {
let hash = { } ;
for ( let i = 0 ; i < t. length; i++ ) {
if ( ! hash[ t[ i] ] ) hash[ t[ i] ] = [ ] ;
hash[ t[ i] ] . push ( i) ;
}
let lastMaxIndex = 0 ;
for ( let i = 0 ; i < s. length; i++ ) {
if ( hash[ s[ i] ] ) {
const index = binarySearch ( hash[ s[ i] ] , lastMaxIndex) ;
console. log ( 'index' , index, hash[ s[ i] ] ) ;
if ( index === - 1 ) return false ;
lastMaxIndex = hash[ s[ i] ] [ index] + 1 ;
} else return false ;
}
return true ;
} ;
function binarySearch ( array, targetIndex ) {
let left = 0 , right = array. length;
while ( left < right) {
let mid = left + Math. floor ( ( right - left) / 2 ) ;
if ( array[ mid] >= targetIndex) {
right = mid;
} else if ( array[ mid] < targetIndex) {
left = mid + 1 ;
}
}
if ( left >= array. length || array[ left] < targetIndex) return - 1 ;
return left;
}
3. 在排序数组中查找元素的第一个和最后一个位置(中等)
var searchRange = function ( nums, target ) {
const left = leftBound ( nums, target) ;
const right = rightBound ( nums, target) ;
return [ left, right] ;
} ;
function leftBound ( nums, target ) {
let left = 0 ;
let right = nums. length - 1 ;
while ( left <= right) {
let mid = Math. floor ( left + ( right - left) / 2 ) ;
if ( nums[ mid] === target) {
right = mid - 1 ;
} else if ( nums[ mid] < target) {
left = mid + 1 ;
} else if ( nums[ mid] > target) {
right = mid - 1 ;
}
}
if ( left >= nums. length || nums[ left] !== target) {
return - 1 ;
}
return left;
}
function rightBound ( nums, target ) {
let left = 0 ;
let right = nums. length - 1 ;
while ( left <= right) {
let mid = Math. floor ( left + ( right - left) / 2 ) ;
if ( nums[ mid] === target) {
left = mid + 1 ;
} else if ( nums[ mid] < target) {
left = mid + 1 ;
} else if ( nums[ mid] > target) {
right = mid - 1 ;
}
}
if ( right < 0 || nums[ right] !== target) {
return - 1 ;
}
return right;
}