刷刷刷刷算法

链表

24. 两两交换链表中的节点
/**
 * 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
};
//首先创建虚拟头节点,然后用临时节点把要操作的节点保存下来,再交换位置,结束的条件为节点的下一个节点或者下下个为空
//注意点,不要操作空指针
142. 环形链表 II
/**
 * 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相遇的点为开始点
//注意点,不要操作空指针
19. 删除链表的倒数第 N 个结点
/**
 * 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即可
15. 三数之和
/**
 * @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做去重
18. 四数之和
/**
 * @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可能为负数

哈希表

242. 有效的字母异位词
/**
 * @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则进行--
349. 两个数组的交集
/**
 * @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
1. 两数之和
/**
 * @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
454. 四数相加 II
/**
 * @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)即可,有则加次数

字符串

151. 反转字符串中的单词
/**
 * @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为数字长度时进行局部反转
//最后变回字符串
459. 重复的子字符串
/**
 * @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

栈和队列

1047. 删除字符串中的所有相邻重复项
/**
 * @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入栈
 150. 逆波兰表达式求值
/**
 * @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];
};
//循环遍历数组,当为符号的时候对栈的最后两个元素进行计算,将结果入栈,如果不为符号则入栈
 239. 滑动窗口最大值
/**
 * @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,目的让对头是最大元素,只有当出队元素和辅助队头元素相等时才会在辅助队列里面出队

二叉树

144. 二叉树的前序遍历
//迭代法
/**
 * 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,表示当前节点已经访问过左后孩子节点了
145. 二叉树的后序遍历
/**
 * 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;
};
94. 二叉树的中序遍历
/**
 * 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
};
226. 翻转二叉树
/**
 * 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
};
//返回的是节点 通过前序遍历实现,交换左右孩子
101. 对称二叉树
/**
 * 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

贪心算法

455. 分发饼干
/**
 * @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时,结束
376. 摆动序列
/**
 * @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时,结束
53. 最大子数组和
/**
 * @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,因为如果是负数的话,加上前面的值只会更小
122. 买卖股票的最佳时机 II
/**
 * @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则相加
 55. 跳跃游戏
/**
 * @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
 45. 跳跃游戏 II
/**
 * @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++
1005. K 次取反后最大化的数组和
/**
 * @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则对最后一个元素进行取反
134. 加油站
//暴力解法
/**
 * @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

  • 8
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
转弯限制的A*算法是一种路径规划算法,专门考虑路径转弯约束以及路径起始/目标角要求。该算法通过引入方向约束来区分同一路径点处不同方向的各条路径,并采用定向扩展机制来满足路径方向约束。此外,该算法还采用节点合并策略来优化路径搜索过程,提高搜索效率。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [基于方向约束的A*算法](https://download.csdn.net/download/weixin_38675967/14139904)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [LeetCode·每日一题·2681. 英雄的力量·脑筋急转弯](https://blog.csdn.net/m0_64560763/article/details/132036704)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [算法刷刷刷(一、递归)](https://blog.csdn.net/weixin_45743162/article/details/122847940)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值