无重复字符的最长子串
题解:
哈希+双指针,哈希保存char的坐标,如果出现重复字符就移动窗口
var lengthOfLongestSubstring = function(s) { if(s.length===0) return 0; let left=0; let maxLength = 0; const map = new Map(); for(let right=0; right<s.length; right++){ const char = s[right]; if(map.has(char)){ left = Math.max(left,map.get(char)+1)//保证窗口一直向右滑动 } map.set(char,right) maxLength = Math.max(maxLength,right-left+1) } return maxLength;};
LRU缓存
题解:双向链表
反转链表
题解:
保留三个指针:prev,current,next,前两个交换指向,后一个保留链表的引用
数组中第k大
题解:快排
var findKthLargest = function (nums, k) { const targetIndex = nums.length - k; return quickSelect(0, nums.length - 1, targetIndex, nums);};const quickSelect = (left, right, k, arr) => { if (left === right) return arr[left]; const pivotIndex = partition(left, right, arr); if (k === pivotIndex) { return arr[pivotIndex]; } else if (k < pivotIndex) { return quickSelect(left, pivotIndex - 1, k, arr); } else { return quickSelect(pivotIndex + 1, right, k, arr); }};const partition = (left, right, arr) => { const pivot = arr[left]; let l = left + 1; let r = right; while (l <= r) { while (l <= r && arr[l] <= pivot) { l++; } while (l <= r && arr[r] > pivot) { r--; } if (l < r) { //重要,确保不要打乱已分区的部分 [arr[l], arr[r]] = [arr[r], arr[l]]; } } // 将基准值放到正确位置 [arr[left], arr[r]] = [arr[r], arr[left]]; return r;};
快排
注意点:
-
if(left >= right) return;
-
while(l<=r)
var sortArray = function(nums) { quickSort(0,nums.length-1,nums) return nums;};function quickSort(left,right,arr){ // 空数组时会出现left>right if(left >= right) return; const pivotIndex = partition(left,right,arr); quickSort(left,pivotIndex-1,arr); quickSort(pivotIndex+1,right,arr);}function partition(left,right,arr){ const pivot = arr[left] let l = left+1; let r = right; while(l<=r){ while(l<=r && arr[l]<=pivot){ l++; } while(l<=r && arr[r]>pivot){ r--; } if(l<r){ [arr[l],arr[r]]=[arr[r],arr[l]] } } [arr[left],arr[r]]=[arr[r],arr[left]] return r;}
K个一组反转链表
题解:
第一个节点:空节点dummy ---> 初始prev
第二个节点:head ---> 初始cur
1、写一个反转函数,返回newHead,newTail,nextGroup
2、反转前判断是否足k个
3、反转后连接链表,移动指针:上一组和这一组连接,这一组和下一组连接,更新pre和cur指针
var reverseKGroup = function(head, k) { // 辅助函数:反转链表的前 k 个节点 function reverse(prev, head, k) { let current = head; while (k > 0 && current) { const next = current.next; current.next = prev; prev = current; current = next; k--; } return { newTail: head, newHead: prev, nextGroup: current }; } // 处理空链表 if (!head) return null; const dummy = new ListNode(0); dummy.next = head; let prevGroupTail = dummy; // 上一组的尾节点 let current = head; while (true) { // 检查剩余节点是否足够 k 个 let temp = current; let count = k; while (count > 0 && temp) { temp = temp.next; count--; } if (count > 0) break; // 不足 k 个,直接退出 // 反转当前 k 个节点 const { newTail, newHead, nextGroup } = reverse(prevGroupTail, current, k); // 连接反转后的组 prevGroupTail.next = newHead;//连接上一组和这一组 newTail.next = nextGroup;//连接这一组和下一组 prevGroupTail = newTail; // 更新prev为这一组的尾节点 current = nextGroup; // 移动到下一组 } return dummy.next;};
三数之和
题解:排序➕双指针
排序之后方便跳过重复的数字,以及根据结果大小决定左右指针移动的方向
var threeSum = function (nums) { const res = []; const len = nums.length; nums.sort((a, b) => a - b) for (let i = 0; i < len; i++) { if (nums[i] > 0) break; if (i > 0 && nums[i] === nums[i - 1]) continue; let left = i + 1; let right = len - 1; while (left < right) { const sum = nums[i] + nums[left] + nums[right]; if (sum === 0) { res.push([nums[i], nums[left], nums[right]]); //跳过后续重复的数字 while (left < right && nums[left] === nums[left + 1]) { left++; } while (left < right && nums[right] === nums[right - 1]) { right--; } //正常移动 left++; right--; } else if (sum < 0) { left++; } else { right--; } } } return res;};
最大子数组和
题解:动态规划
以该元素结尾时的最大和(要么加上前面的部分,要么从这个数字重新开始)
var maxSubArray = function(nums) { let curSum = nums[0]; let maxSum = nums[0]; for(let i=1; i<nums.length; i++){ // 以该元素结尾的最大和(要么加上前面的部分,要么从这个数字重新开始) curSum = Math.max(nums[i],curSum+nums[i]); // 全局最大和 maxSum = Math.max(maxSum,curSum) } return maxSum;};
最长回文子串
方法一:动态规划
题解:比较s[i]、s[j],若相等则取决于dp[i+1][j-1]是否为回文
var longestPalindrome = function(s) { const n = s.length; if(n<2) return s; let maxLen = 1; let begin = 0; const dp = Array.from({length:n},()=>Array.from({length:n},() => false)) for(let i=0; i<n; i++){ dp[i][i]=true; } for(let j=1; j<n; j++){ for(let i=0; i<j; i++){ if(s[i] != s[j]){ dp[i][j] = false; }else{ if(j-i<3){ dp[i][j]=true; }else{ dp[i][j] = dp[i+1][j-1]; } if(dp[i][j] && j-i+1>maxLen){ maxLen = j-i+1; begin = i; } } } } return s.substring(begin,begin+maxLen)};
方法二:中心扩散法(更优解)
题解:
从中心向外同步扩散,如果相等就继续扩散
注意奇数是从i扩散,偶数从i和i+1扩散
var longestPalindrome = function(s) { const len = s.length; if(len<2) return s; let res=''; for(let i=0; i<len; i++){ helper(i,i) helper(i,i+1) } function helper(m,n){ while(m>=0 && n < len && s[m]===s[n]){ m--; n++; } if(n-m-1 > res.length){ res = s.slice(m+1,n) } } return res;};