10.17(滑动窗口 sliding window(技巧) 209/1456)
时间复杂度不要看是两个循环嵌套就认为是O(n^2),看元素的操作次数,元素在right移动时进来一次,left移动时出去一次所以是2n次,时间复杂度O(n)。
var minSubArrayLen = function(target, nums) {
// 长度计算一次
const len = nums.length;
let l = r = sum = 0,
res = len + 1; // 子数组最大不会超过自身
while(r < len) {
sum += nums[r++];
// 窗口滑动
while(sum >= target) {
// r始终为开区间 [l, r)
res = res < r - l ? res : r - l;
sum-=nums[l++];
}
}
return res > len ? 0 : res;
};
10.19递归 recursion 509/206/344/687
// // 普通递归
// var fib = function(n) {
// if(n==0) return 0;
// if(n==1) return 1;
// return fib(n-1)+fib(n-2)
// };
// 递归记忆(因为太递归调用的过程会遇到重复计算,例如meno[10]=meno[9]+meno[8],而在计算meno[9]的时候又需要计算meno[8],所以可以用一个数组把计算过的储存起来。
var fib =function(n) {
let meno =new Array(n+1).fill(0);
let dfs =(n) =>{
if(n==0) {
return 0
}
if(n==1) {
return 1
}
if(meno[n]) {
return meno[n]
}
meno[n] = dfs(n-1)+dfs(n-2)
return meno[n];
}
return dfs(n)
}
// 递归写法
var reverseList =function(head) {
// 递归终止条件
if(head==null||head.next==null) return head
const p = reverseList(head.next)
head.next.next = head
head.next = null
return p
}
var reverseString = function(s) {
const helper =(curr)=>{
// 当curr到达字符串的中间位置(half)时,停止递归
if(curr==half) {
return
}
// 交换curr和对应位置的字符,实现字符串反转
[s[curr],s[len-curr-1]]=[s[len -curr-1],s[curr]]
// 递归调用helper,将curr增加1
helper(curr+1)
}
let len =s.length
let half=Math.floor(len>>1)
helper(0)
}
const longestUnivaluePath = (root) => {
let res = 0; // 用于存储最长相同值路径的长度
const dfs = (root) => {
if (root == null) {
return 0; // 如果节点为空,返回 0
}
const left = dfs(root.left); // 递归计算左子树的路径长度
const right = dfs(root.right); // 递归计算右子树的路径长度
let leftPath = 0, rightPath = 0;
if (root.left && root.left.val == root.val) {
leftPath = left + 1; // 如果左子节点的值与当前节点相同,更新左子树路径长度
}
if (root.right && root.right.val == root.val) {
rightPath = right + 1; // 如果右子节点的值与当前节点相同,更新右子树路径长度
}
res = Math.max(res, leftPath + rightPath); // 更新最长相同值路径长度
return Math.max(rightPath, leftPath); // 返回当前节点的最长相同值路径长度
}
dfs(root); // 调用递归函数
return res; // 返回最长相同值路径长度
}