如果当前字符已经出现过,并且在当前窗口内(即其位置大于等于 left),则更新 left 指针的位置为该字符上次出现的位置的下一个位置。
如果当前字符没有出现过,或者虽然出现过但不在当前窗口内,则更新最长子字符串的长度。
不断更新最长子字符串的长度,并返回结果。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
var lengthOfLongestSubstring = function(s) { let l=0,r=0,max=0 let map = newMap() while(r<s.length){ //判断map的记录中,这个字符的值是否在滑动窗口内 if (map.has(s[r]) && map.get(s[r]) >= l) { //如果在窗口内l指针指向当前记录值的后一位 l = map.get(s[r])+1 } //如果map中没有当前字符得记录或者有记录但是不在滑动窗口范围内 map.set(s[r], r) max = Math.max(max, r - l + 1) r++ } return max }
判断子序列
解题思路
初始化指针i,j分别指向字符串是,和t的起始位置;其中s是子串,t是较长的字符串
遍历比较s[i]和t[j]的情况
如果s[i]==t[j],那么指向子串的指针+1,即i++;且j++
如果不想等j++
判断子序列:如果 i 移动到了 s 的末尾,则说明 s 是 t 的子序列,返回 true;否则返回 false。
代码
1 2 3 4 5 6 7 8 9 10 11
var isSubsequence = function(s, t) { let i=0,j=0 //处理两个字符串都是空字符串的情况 if (s==t) returntrue while (j<t.length){ if (s[i]===t[j]) i++ j++ } if (i==s.length) returntrue elsereturnfalse };
两数之和
解题思路
使用字典,判断目标值减去当前值的结果是否,存在于字典中。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13
var twoSum = function(nums, target) { let map = newMap() // 判断target-当前元素的结果是否存在于map中,如果存在返回下标 for (let i=0;i<nums.length;i++){ if (map.has(target-nums[i])){ return [map.get(target-nums[i]),i] } //如果不存在,设置当前元素为键,当前元素下表为值 else{ map.set(nums[i],i) } } }
var threeSum = function (nums) { let res = [] nums = nums.sort((a,b)=>a-b) //首先要进行排序 for (let i = 0; i < nums.length-2; i++) { //减2是因为求得是三个元素的和。 if (i > 0 && nums[i] == nums[i - 1]) continue//a去重 let left = i + 1,right = nums.length - 1//指定双指针 while (left < right) { let sum = nums[i]+nums[left]+nums[right] if (sum>0) right-- if (sum<0) left++ 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-- } } } return res }
反转链表
自定义链表
解题代码
1 2 3 4 5 6 7 8 9 10 11 12
var reverseList = function(head) { let prev = null let cur = head while(cur){ // 这一步我忘记了,没有把next的值保存下来,直接给cur.next赋值了 const next = cur.next cur.next = prev prev = cur cur = next } return prev //最后一个cur是null,他前面一个才是第一个有值的节点 };
var preorderTraversal = function (root) { const res = [] constpreorder = (rt)=>{ if (!rt) return res.push(rt.val) preorder(rt.left) preorder(rt.right) } preorder(root) return res }
迭代法
1 2 3 4 5 6 7 8 9 10 11 12 13
var preorderTraversal = function (root) { let res = [] if (!root) return res // 应对空二叉树 let queue = [root] while(queue.length){ //每次从队列里去一个节点,把该节点的值添加到result, let cur = queue.pop() res.push(cur.val) //该节点的右孩子和左孩子依次加入节点, if (cur.right) queue.push(cur.right) //等到下一轮,就会分别依次遍历左孩子和有孩子了 if (cur.left) queue.push(cur.left) } return res }
后序遍历
递归法
1 2 3 4 5 6 7 8 9 10 11
var postorderTraversal = function (root) { let res = [] constpostorder = (rt) => { if (!rt) return//不要忘了这个条件 postorder(rt.left) postorder(rt.right) res.push(rt.val) } postorder(root) return res }
迭代法
1
中序遍历
递归法
1 2 3 4 5 6 7 8 9 10 11
var inorderTraversal = function (root) { let res =[] constinorder = (rt)=>{ if (!rt) return rt.left && inorder(rt.left) res.push(rt.val) rt.right && inorder(rt.right) } inorder(root) return res }
迭代法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
var inorderTraversal = function (root) { // 入栈:左->右 // 出栈:左 中 右 let res = [] const stack = [] if (root) stack.push(root) while (stack.length) { const node = stack.pop() if (!node) { res.push(stack.pop().val) continue } if (node.right) stack.push(node.right) // 右 stack.push(node) // 中 stack.push(null) if (node.left) stack.push(node.left) // 左 } return res }