链表
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var swapPairs = function(head) {
let ret =new ListNode(0,head),temp=ret;
while(temp.next&&temp.next.next) {
let cur=temp.next.next,pre=temp.next;
pre.next=cur.next;
cur.next=pre;
temp.next=cur;
temp=pre;
}
return ret.next
};
//首先创建虚拟头节点,然后用临时节点把要操作的节点保存下来,再交换位置,结束的条件为节点的下一个节点或者下下个为空
//注意点,不要操作空指针
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var detectCycle = function(head) {
let fast=head,slow=head;
if(!head||!head.next) {
return null;
}
while(fast.next&&fast.next.next) {
slow=slow.next;
fast=fast.next.next;
if(fast==slow) {
slow=head;
while(fast!==slow) {
fast=fast.next;
slow=slow.next;
}
return slow
}
}
return null
};
//首先是判断有没有环,快指针每次走两步,慢指针走一步,当他们有相遇时,即为有环,否则返回null
//然后判断哪个是开始的节点,设慢指针走了x+y,快指针走了x+n(y+z)+y 得2(x+y)=x+y+n(y+z) x=(n-1)(y+z)+z 所以x和y相遇的点为开始点
//注意点,不要操作空指针
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @param {number} n
* @return {ListNode}
*/
var removeNthFromEnd = function(head, n) {
let ret =new ListNode(0,head),temp=ret,fast=ret,slow=ret;
while(n-->=0) {
fast=fast.next
}
while(fast) {
fast=fast.next
slow=slow.next
}
slow.next=slow.next.next
return ret.next
};
//首先快指针移动n+1,然后分别移动快慢指针直到快指针为null,改变慢指针的next即可
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
let res=[];
nums.sort((a,b)=>a-b);
for(let i=0;i<nums.length;i++) {
let l=i+1,r=nums.length-1
if(nums[i]>0) return res;
if(nums[i]==nums[i-1]) continue;
while(r>l) {
if(nums[i]+nums[l]+nums[r]<0) {
l++
} else if(nums[i]+nums[l]+nums[r]>0) {
r--
} else {
res.push([nums[i],nums[l],nums[r]])
while(l<r&&nums[l]==nums[l+1]) {
l++
}
while(l<r&&nums[r]==nums[r-1]) {
r--
}
l++
r--
}
}
}
return res
};
//首先对数组进行排序,for循环数组,另第一个元素的下标为i,并做去重处理,即nums[i]!=nums[i-1]
//然后对剩下的进行元素设定,当r>l时继续,如果三个元素的和大于0,则r--,小于0则l++,等于0则push进去,然后对l和r做去重
/**
* @param {number[]} nums
* @param {number} target
* @return {number[][]}
*/
var fourSum = function(nums, target) {
let res=[];
if(nums.length<4) return [];
nums.sort((a,b)=>a-b);
for(let i=0;i<nums.length-3;i++) {
if(i>0&&nums[i]==nums[i-1]) continue;
for(let j=i+1;j<nums.length-2;j++) {
if(j>i+1&&nums[j]==nums[j-1]) continue;
let l=j+1,r=nums.length-1;
while(r>l) {
let sum=nums[i]+nums[j]+nums[l]+nums[r];
if(sum>target) {
r--;
continue;
}
if(sum<target) {
l++;
continue;
}
res.push([nums[i],nums[j],nums[l],nums[r]])
while(l<r&&nums[l]==nums[l+1]) {
l++
}
while(l<r&&nums[r]==nums[r-1]) {
r--
}
l++;
r--
}
}
}
return res
};
//与三数和思路差不多,多了一层for循环,且target可能为负数
哈希表
/**
* @param {string} s
* @param {string} t
* @return {boolean}
*/
var isAnagram = function(s, t) {
if(s.length!==t.length) return false;
let arr =new Array(26).fill(0);
let base = 'a'.charCodeAt();
for(const i of s) {
arr[i.charCodeAt()-base]++;
}
for(const i of t) {
if(!arr[i.charCodeAt()-base]) return false
arr[i.charCodeAt()-base]--;
}
return true;
};
//数据范围小数量小用数组,反正用set,有key value用map
//用哈希特性,首先遍历第一个数组,出现的进行++,第二个数组首先如果有为0的即与第一个数组有不同的元素,不为0则进行--
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number[]}
*/
var intersection = function(nums1, nums2) {
if(nums1.length<nums2.length) {
const temp = nums1;
nums1 = nums2;
nums2 = temp;
}
const nums1Set=new Set(nums1);
const resSet = new Set();
// for(const n of nums2) {
// nums1Set.has(n) && resSet.add(n)
// }
for(let i =0;i<nums2.length;i++) {
nums1Set.has(nums2[i])&&resSet.add(nums2[i])
}
return Array.from(resSet)
};
//利用set特性,再for循环num2里的元素,检查num1中是否有,有则add
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) {
let resMap=new Map();
for(let i=0;i<nums.length;i++) {
var tar=target-nums[i]
if(resMap.has(tar)) {
return [i,resMap.get(tar)]
}
resMap.set(nums[i],i)
}
};
//new一个map,for循环遍历数组,用目标值-当前值获取要找的值,检查map里是否有,有则返回,没有则加入map
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @param {number[]} nums3
* @param {number[]} nums4
* @return {number}
*/
var fourSumCount = function(nums1, nums2, nums3, nums4) {
const hash = new Map();
let res =0,len=nums1.length;
for(let i =0;i<len;i++) {
for(let j =0;j<len;j++) {
const sum=nums1[i]+nums2[j];
let num = hash.get(sum)||0;
hash.set(sum,++num)
}
}
for(let i =0;i<len;i++) {
for(let j =0;j<len;j++) {
const sum=-(nums3[i]+nums4[j]);
if(hash.has(sum)) {
res+=hash.get(sum)
}
}
}
return res
};
//22分组for循环,第一个记录值为key,次数为value,因为n1+n2+n3+n4=0所以n1+n2=-(n3+n4),在第二个中寻找-(n3+n4)即可,有则加次数
字符串
/**
* @param {string} s
* @return {string}
*/
var reverseWords = function(s) {
const str=Array.from(s);
var reverse=function(s,start,end) {
while(start<end) {
[s[start],s[end]]=[s[end],s[start]]
start++;
end--;
}
}
var remove=function(s) {
let slow=0;
let fast=0;
while(fast<s.length) {
if(s[fast]===' '&&(fast===0||s[fast-1]===' ')) {
fast++
} else {
s[slow]=s[fast];
slow++;
fast++;
}
}
s.length=s[slow-1]===' '?slow-1:slow
}
remove(str);
reverse(str,0,str.length-1);
let start=0;
for(let i=0;i<=str.length;i++) {
if(str[i]===' '||i===str.length) {
reverse(str,start,i-1);
start=i+1;
}
}
return str.join('')
};
//首先对字符进行数组化,然后进行去空格处理,当fast指针为空且fast-1为空或者index=1时,不进行赋值给慢指针,直接指向下个.
//然后对数字进行反转
//然后对单词进行反转,即当遇到空格时,或者i为数字长度时进行局部反转
//最后变回字符串
/**
* @param {string} s
* @return {boolean}
*/
var repeatedSubstringPattern = function(s) {
const n =s.length;
for(let i=1;i<=Math.floor(n/2);i++) {
if(n%i===0) {
const sub=s.substring(0,i)
let j= i;
while(j<n&&s.substring(j,j+i)===sub) {
j+=i
}
if(j===n) {
return true
}
}
}
return false
};
//for循环字符串当截取i个数可以余数为0时判断是否为子串,首先截取子串,然后while循环不断向后截取,判断是否和初始子串相同,如果相同,则长度相加
//最后判断while循环的字符串长度和给出字符串长度是否相同,相同则返回true
栈和队列
/**
* @param {string} s
* @return {string}
*/
var removeDuplicates = function(s) {
let stack=[];
for(let item of s) {
if(stack[stack.length-1]===item) {
stack.pop()
} else {
stack.push(item)
}
}
return stack.join('')
};
//for循环遍历字符串,判断栈的最后一个元素是否和当前item相等,相等则出栈,否则把item入栈
/**
* @param {string[]} tokens
* @return {number}
*/
var evalRPN = function(tokens) {
let stack = [];
let sign = ['+', '-', '*', '/'];
for (let item of tokens) {
if (sign.includes(item)) {
let operand2 = stack.pop();
let operand1 = stack.pop();
let result;
switch (item) {
case '+':
result = operand1 + operand2;
break;
case '-':
result = operand1 - operand2;
break;
case '*':
result = operand1 * operand2;
break;
case '/':
result = operand1 / operand2;
break;
}
stack.push(Math.trunc(result)); // 保留整数部分
} else {
stack.push(parseInt(item)); // 将字符串转换为整数
}
}
return stack[0];
};
//循环遍历数组,当为符号的时候对栈的最后两个元素进行计算,将结果入栈,如果不为符号则入栈
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var maxSlidingWindow = function(nums, k) {
//定义一个单调队列类
class MonoQueue {
queue;
constructor() {
this.queue=[]
}
// 入队操作
enqueue(value) {
let back=this.queue[this.queue.length-1]
while(back!==undefined&&back<value) {
this.queue.pop();
back=this.queue[this.queue.length-1]
}
this.queue.push(value)
}
// 出队操作
dequeue(value) {
let front =this.front();
if(front === value) {
this.queue.shift()
}
}
front() {
return this.queue[0]
}
}
let queue=new MonoQueue();
let i=0,j=0;
let res=[];
while(j<k) {
queue.enqueue(nums[j++])
}
res.push(queue.front())
while(j<nums.length) {
queue.enqueue(nums[j]);
queue.dequeue(nums[i]);
res.push(queue.front());
i++;
j++
}
return res
};
//构造一个单调队列,入队时检查前面有没有比入队元素小的,有则pop,目的让对头是最大元素,只有当出队元素和辅助队头元素相等时才会在辅助队列里面出队
二叉树
//迭代法
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number[]}
*/
var preorderTraversal = function(root,res=[]) {
const stack =[];
if(root) stack.push(root);
while(stack.length) {
const node=stack.pop();
if(node===null) {
res.push(stack.pop().val);
continue;
}
if(node.right) stack.push(node.right);
if(node.left) stack.push(node.left);
stack.push(node);
stack.push(null)
}
return res
};
//二叉树前序遍历,利用栈实现,首先把当前节点push进去栈,然后开始while循环,条件为当栈不为空,然后把栈顶元素pop,然后检查是否为null,null的话则把下一个栈的下一个元素pop并存储到res中并continue执行下一个循环
//如果不为null,则把右节点先加进去,然后把左节点加进去,最后把当前节点加进去,再加进去一个null,表示当前节点已经访问过左后孩子节点了
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number[]}
*/
var postorderTraversal = function(root,res=[]) {
const stack=[];
if(root) stack.push(root);
while(stack.length) {
const node=stack.pop();
if(!node) {
res.push(stack.pop().val);
continue;
}
stack.push(node);
stack.push(null);
if(node.right) stack.push(node.right)
if(node.left) stack.push(node.left)
}
return res;
};
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number[]}
*/
var inorderTraversal = function(root,res=[]) {
const stack=[];
if(root) stack.push(root)
while(stack.length) {
const node=stack.pop();
if(node===null) {
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
};
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {TreeNode}
*/
var invertTree = function(root) {
if(root===null) return null;
let temp =root.right;
root.right=root.left;
root.left=temp;
invertTree(root.left)
invertTree(root.right)
return root
};
//返回的是节点 通过前序遍历实现,交换左右孩子
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {boolean}
*/
var isSymmetric = function(root) {
const compare=function(left,right) {
if(left===null&&right!==null||left!==null&&right===null) {
return false
} else if(left===null&&right===null) {
return true
} else if(left.val!==right.val) {
return false
}
let outSide=compare(left.left,right.right);
let inSide=compare(left.right,right.left);
return outSide&&inSide
}
if(root===null) return true;
return compare(root.left,root.right)
};
//设定一个函数,比较左右孩子的值是否相等,如果相等,则比较左孩子的左侧节点和右孩子的右侧节点是否相等,左孩子的右侧节点和右孩子的左侧节点
//是否相等,当两个都相等时返回true,然后一直递归遍历下去,所有为true则返回true
贪心算法
/**
* @param {number[]} g
* @param {number[]} s
* @return {number}
*/
var findContentChildren = function(g, s) {
g=g.sort((a,b)=>a-b);
s=s.sort((a,b)=>a-b);
let num=0,j=s.length-1;
for(let i=g.length-1;i>=0;i--) {
if(j>=0&&s[j]>=g[i]) {
num++;
j--;
}
}
return num
};
//首先对数组进行排序,从小到大,从大到小遍历孩子,里面if语句从大到小遍历饼干,当饼干大于等于孩子时,饼干才遍历到下一个,并且num++,当其中一个小于0时,结束
/**
* @param {number[]} g
* @param {number[]} s
* @return {number}
*/
var findContentChildren = function(g, s) {
g=g.sort((a,b)=>a-b);
s=s.sort((a,b)=>a-b);
let num=0,j=s.length-1;
for(let i=g.length-1;i>=0;i--) {
if(j>=0&&s[j]>=g[i]) {
num++;
j--;
}
}
return num
};
//首先对数组进行排序,从小到大,从大到小遍历孩子,里面if语句从大到小遍历饼干,当饼干大于等于孩子时,饼干才遍历到下一个,并且num++,当其中一个小于0时,结束
/**
* @param {number[]} nums
* @return {number}
*/
var maxSubArray = function(nums) {
let res=nums[0];
let count=0;
for(let i=0;i<nums.length;i++) {
count+=nums[i];
if(count>res) res=count;
if(count<0) count=0;
}
return res
};
//for循环找,令当前和为前面的值加上当前遍历的值,判断如果count>res则给res赋值,如果count<0的话,则令count=0,因为如果是负数的话,加上前面的值只会更小
/**
* @param {number[]} prices
* @return {number}
*/
var maxProfit = function(prices) {
let res=0;
for(let i=0;i<prices.length-1;i++) {
if(prices[i+1]>prices[i]) res+=prices[i+1]-prices[i]
}
return res
};
//后一个元素减去前一个元素,大于0则相加
/**
* @param {number[]} nums
* @return {boolean}
*/
var canJump = function(nums) {
let cover=0;
for(let i=0;i<=cover;i++) {
if(i+nums[i]>cover) {
cover=i+nums[i]
}
if(cover>=nums.length-1) return true
}
return false
};
//判断元素可以覆盖的举例,当下一个元素的覆盖范围比前面赋值的cover大的话,则赋值,当cover大于nums.length时返回true
/**
* @param {number[]} nums
* @return {number}
*/
var jump = function(nums) {
let curIndex=0;
let nextIndex=0;
let steps=0;
for(let i=0;i<nums.length-1;i++) {
nextIndex=Math.max(i+nums[i],nextIndex)
if(i===curIndex) {
curIndex=nextIndex;
steps++
}
}
return steps;
};
//设置三个变量,当前覆盖距离,下一个元素可覆盖距离,for循环,当下一个可覆盖距离更大时则重新赋值,当当前覆盖距离等于i时,代表已经跳到了当前的最大距离,需要再跳,使用step++
/**
* @param {number[]} nums
* @param {number} k
* @return {number}
*/
var largestSumAfterKNegations = function(nums, k) {
let sum=0;
nums.sort((a,b)=>Math.abs(b)-Math.abs(a));
for(let i=0;i<nums.length;i++) {
if(nums[i]<0&&k>0) {
nums[i]=-nums[i];
k--;
}
sum+=nums[i]
}
if(k%2!==0) {
sum-=2*nums[nums.length-1]
}
return sum
};
//根据绝对值大小从大到小排序,for循环,如果k大于0且当前遍历的值小于0,则取反,当遍历完还有剩余的k则对最后一个元素进行取反
//暴力解法
/**
* @param {number[]} gas
* @param {number[]} cost
* @return {number}
*/
var canCompleteCircuit = function(gas, cost) {
for(let i=0;i<cost.length;i++) {
let rest=gas[i]-cost[i];
let index=(i+1)%cost.length;
while(rest>0&&index!==i) {
rest+=gas[index]-cost[index];
index=(index+1)%cost.length;
}
if(rest>=0&&index===i) return i;
}
return -1
};
//暴力解法:第一个for循环遍历起点,计算当前累计油量量,令index等于(index+1)%length,然后执行下一个循环直到rest小于0或者index回到i
/**
* @param {number[]} gas
* @param {number[]} cost
* @return {number}
*/
var canCompleteCircuit = function(gas, cost) {
const gasLen=gas.length;
let start=0;
let curSum=0;
let totalSum=0;
for(let i=0;i<gasLen;i++) {
curSum+=gas[i]-cost[i];
totalSum+=gas[i]-cost[i];
if(curSum<0) {
curSum=0;
start=i+1
}
}
if(totalSum<0) return -1;
return start
};
//for循环累加total,同时累加cur,当cur小于0时,重新赋值cur为0,start为i+1,因为前面的已经没有足够的油,使用前面不能作为起始点
//最后判断total是否大于0,大于则返回start,否则返回-1