力扣刷题算法笔记(javascript版)下

上篇链接:
力扣刷题算法笔记(javascript版)上

视频链接:
人人都能看得懂的Leetcode力扣刷题教程合集

在笔记上中 一共学习了31道算法题,剩下大概20到算法题在花两天的学习和总结一下

1、 打家劫舍

题目描述:
你是一个专业的小偷 计划投钱沿街的房屋,每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通防盗系统 (所以不能偷相邻的两家)
给定一个代表每个房屋能存放金额的非负整数数组 计算你在不触动警报装置下 能偷到的最高金额。
在这里插入图片描述
不能偷相邻的房子 动态规划 记录到当前这个房子能收到的最大数
思路就是设定一值用来保存 然后动态的去比较相加的代码

//   33  打家劫舍
var rob = function(nums){
    
    
// 数组长度为0和1 的情况
    if(nums.length == 0){
    
    
        return 0;
    }
    if(nums.length === 1){
    
    
        return nums[0];
    }
    const memo = [];
    memo [0] = nums[0];
    memo[1] = Math.max(nums[0],nums[1]);
    for(let i = 2; i<nums.length;i++){
    
    
        //判断一下是选择在当前房子还是保留i-1最大的数
        memo[i] = Math.max(nums[i] + memo[i-2],memo[i-1]) 
    }
    return memo[nums.length -1] ;//返回最后一个数
}

// 优化  在选择偷哪一个数组的时候可以优化 不需要单独的变量 
//直接是用两个需要定义的变量

var rob = function(nums){
    
    
    // 数组长度为0和1 的情况
        if(nums.length == 0){
    
    
            return 0;
        }
        if(nums.length === 1){
    
    
            return nums[0];
        }
        
        let prev2 = nums[0];
        let prev1 = Math.max(nums[0],nums[1]);
        for(let i = 2; i<nums.length;i++){
    
    
            //判断一下是选择在当前房子还是保留i-1最大的数
            const temp = Math.max(nums[i] + memo[i-2],memo[i-1]) ;
            prev2 = prev1;
            prev1 = temp;
        }
        return prev1;
    }

2、岛屿数量

题目描述:给定一个有‘1(陆地)和0(水)组成的二维网络,
并且他是通过水平方向活垂直方向上相邻的陆地连接而成的,可以假设网格的四个边均被水包围了
在这里插入图片描述
在这里插入图片描述
分析思路:从最开始遍历访问 如果是1就记录下来 记作一个小岛,然后他周围是1的部分都是一个小岛 这里用到“沉没”就是把1全部变成0 这样接着往后面遍历 就不存在重复的问题了,最后就能数出小岛的数量
那么重点在于沉没这个过程:
把当前的点从1变为0 然后从这个点向周围(行和列)扩散 判断是否越界(越界取消)是0的话就不做操作· 判断是1就变为0 然后在这个基础上继续扩散检查 和之前的步骤一样;最后返回小岛的数量

bfs:广度优先搜索:
dfs:深度优先搜索:
代码实现:

    //判断岛屿数量
var numIslands = function (grid){
    
    
    let count = 0;//初始化小岛的数量为0
    function dfs(row,col){
    
    
        //判断越界和等于0的时候  不需要去处理
        if(row<0 || row >= grid.length || col<0 || col>=grid[0].length || grid[row][col] === "0"){
    
    
            return;
        }
      
        //如果不是1 则变为0 然后的调用  这里采用了递归的方法
        grid[row][col] = "0";
        dfs(row-1,col);
        dfs(row+1,col);
        dfs(row, col-1);
        dfs(row ,col+1);
    }
    //遍历二维数组:
    for(let row = 0;row<grid.length;row++){
    
    
        for(let col=0;col<grid[0].length; col++){
    
    
            if(grid[row][col] === "1"){
    
    //这里使用字符串1
                count++;//增加小岛数量
                dfs(row,col);//sink就是沉没函数 dfs

            }
        }
    }
    return count;
}

3、反转链表

链表的题 主要是玩指针
在这里插入图片描述
在这里插入图片描述

解题思路:
一、利用栈 (先进后出)的特点 然后在一个一个取出来 会多开一个数组
二、分四部 需要三个指针 prev curr next
初始:prev指向第一个节点前的空节点 curr指向第一个节点 next也指向第一个节点
第一步 next指向curr后一个节点 也就是第二个
第二步:curr的next指向prev (就是1指向0)
第三步:prev像后挪一步 prev= curr
第四步: curr指向next
这样就完成了一次反转 循环遍历到最后 当curr为空的时候 最后返回的是prev(因为已经反转了)

//反转链表 传统写法
var reverseList = function (head){
    
    
    let prev = null;
    let curr = head ;
    let next = null;
    while(curr !== null){
    
    
        next = curr.next;
        curr.next = prev; //指向反转
        prev = curr;
        curr = next;
    }
    return prev;
}
//ES6中解构赋值 可以直接使用

4、存在重复元素

描述:给定一个数组 判断是否存在重复元素 如果任何值在数组中都至少出现两次 函数返回true 如果数组中每个元素都不相同 则返回false
在这里插入图片描述
自己的解题思路:1、遍历 放入新数组比较/2、使用两个set 3.查找每个数组中出现数字的次数
利用数据结构 set中has属性 如果所有元素都返回has的话就最后返回true 否则返回false

// 存在重复元素
var containDuplicate = function (nums){
    
    
    const set = new Set();
    for(let i = 0;i<nums.length; i++){
    
    
        if(set.has(nums[i])){
    
    
            return true;
        }
        set.add(nums[i]);
    }
    return false;
}

5、存在重复元素2

描述:给定一个整数数组和一个整数k 判断数组中是否存在两个不同的索引i和j 是的nums[i]=nums[j[ 并且i和j的差的绝对值最大为k
判断在k个元素内有没有重复的元素
在这里插入图片描述
解题思路:使用map 遍历数组每个数 然后存到map里面 map的key设置为数组的值 value为值的索引,判断这个数在map中有没有 没有就把值和index放进去。 后续放进去重复的数字的时候 需要判断他们的索引值 相减的绝对值是否小于等于k 是的话就返回true 不是的话就继续 但是需要把当前重复的更新到后面重复这个值

代码实现:

// 存在重复元素
var containsNearDuplicate = function(nums,k){
    
    
    const map = new Map();//新建一个map用来存放数组 (主要用到index值)
    for(let i= 0;i<nums.length;i++){
    
    
    //如果没有i或者两个重复的i值小于k 返回true
        if(map.has(nums[i]) && (i-map.get(nums[i])  <=k)){
    
    
            return true;
        }else{
    
    //没有的话就正常插入
            map.set(nums[i],i);
        }
    }
    return false;
}

6、除自身以外数组的乘积

给定长度为n的整数数组nums,其中n>1 返回输出数组output、, 其中output【i】等于nums中除nums【i】之外其余各元素的乘积,
在这里插入图片描述
注:不能使用除法 且在0(n)时间复杂度内完成此题,
解题思路:如果没有注释 思路我觉得是全部乘积起来 然后除以nums[i]
i左边的相程 右边的乘积乘起来 然后在相乘 可以使用动态规划
需要两个表格 一个是从左到右的乘积 林外一个是从右到左的乘积
在这里插入图片描述
优化:使用一个变量 不断更新 使用5的值的时候那个变量乘于4的值

代码实现:

var productExcptSelf = function (nums){
    
    
    const result = Array(nums.length).fill(1);
    let product = 1;
    for(let i = 0; i<nums.length;i++){
    
    
        result[i] = result[i] * product;
        product = product * numns[i];
    }
    for(let i = nums.length-1; i>=0;i--){
    
    
        result[i] = result[i] * product;
        product = product * numns[i];
    }
    return result;
};

7 vaild Anagram

Anagram 的意思就是 一个单词可以通过调换顺序得到另一个单词 第一个单词里面每一个词出现的次数和第二个出现的次数一样
给定两个数组 判断这两个数组哈斯不会Anagram
Palindrome:单词从前面往后面的顺序和从后面往前面的顺序一样的

解题思路:
1、判断两个数组长度是否一直 不一致返回false
2、创建一个map 用来存储每个字符出现的次数
3、对于第一个单词的每个字母 也就是S1[i] 在map里将出现次数+1。对于第二个单词的每个字母 也就是s2[i] 在map里将出现次数-1,
4、遍历完成之后 检查map里的每一个字母出现次数是否是0 如果有一个非0的字母 则返回false 否则返回true;
代码实现:

//Anagram
 var isAnagram = function(s,t){
    
    
     //判断两个数组是否一致
     if(s.length !== t.length){
    
    
         return false;
     }
     const map = new Map();
    //  用一个for循环遍历两个数组
     for(let i=0;i<s.length;i++){
    
    
         if(map.has(s[i])){
    
    
            //  如果map有s[i] value就需要加一
             map.set(s[i],map.get(s[i])+1);
         }else{
    
    
             map.set(s[i],1);
         }
         if(map.has(t[i])){
    
    
            //  如果t有t[i]的话 value需要减一
            map.set(t[i],map.get(t[i]) - 1);
        }else{
    
    //没有就初始化为-1
            map.set(t[i],-1);
        }
     }
     //遍历map的时候使用map.forEach返回的是一个函数 不能返回外面的函数 
    //  需要使用for of 需要是哟const
     for (const letter of map){
    
    
         //letter的第二个如果不是0 的话 
        if(letter[1] !== 0){
    
    
            return false;
        }
     }
     return true;
 }

8、移动零

题目描述:给定一个数组nums 编写一个函数将所有的0移动到数组的末尾 同时保持非零元素的相对顺序(之前的顺序)
在这里插入图片描述
注:
1、必须在原数组上进行操作,不能拷贝额外的数组
2、尽量减少操作次数
解题思路:
不是一个一个换 把非零的数进行排序 剩余的位置填充0
需要两个指针:i j
先移动i i++ 如果i遇到的是0 则跳过继续下一个 如果不是0,把当前i的位置赋值给j 然后j++
当i移动到最后的时候 就把j后面的数都变成0
i移动的时候 o跳过数值交换 这样确保了相对的顺序 最后在进行0的填充 这样0就变到了最后面。
代码实现:

//  移动0
var moveZeroes = function (nums){
    
    
    let j = 0;
    for(let i= 0;i<nums.length; i++){
    
    
        if(nums[i] !== 0){
    
    
            nums[j] = nums[i];
        j++;        }
    }
    //上面循环完一遍之后把j后面的数字全部变化成0
    for (i=j;i<nums.length; i++){
    
    
        nums[i] = 0;
    }
    return nums;
}

9 奇偶链表

描述:给定一个单链表 吧所有的奇数节点和偶数节点分别排在一起 奇数和偶数值指的是index位置的奇偶数 不是数值的奇偶 奇数排到前面 偶数排到后面
在这里插入图片描述
请尝试用原地算法完成 空间复杂度为0(1)
解题思路: 需要两个指针 第一个在第一位(第一个奇数结点)第二个指针
在这里插入图片描述
1指向3 2指向4 然后循环这个过程 最后把7指向2
代码实现:

// 奇偶链表
var oddEvenList = function (head){
    
    
    //判断两种特殊情况
    if(head === null){
    
    
        return null;
    }
    if(head.next === null){
    
    
        return head;
    }
    //定义两个指针
    let  odd =head //奇数
    let even = head.next;
    let evenHead = head.next; //把偶数的头部占住 后面要连接奇数的尾部
    //判断是否循环结束作为条件
    while(even !== null && even.next !== null){
    
    
        //这里为什么不能直接使用3次next呢 
        odd.next = odd.next.next;
        odd = odd.next;
        even.next =even.next.next;
        even = even.next;
    }
    odd.next= evenHead;//把奇数尾部指向偶数头部
    return head;
}

10、两个数组的交集

描述:给定两个数组 判断他们的交集
在这里插入图片描述
注:输出结果中每个数都是唯一的 不考虑输出数组的顺序
思路解析:
个人:使用map 两个数组往里面插入 value大于1的就是交集
不能重复 就使用set
循环判断数组里面是否有相同的数
代码实现:

// 两个数组的交集
var intersection = function(nums1,nums2){
    
    
    const result = new Set();
   
    for(nums2.includes(nums)){
    
    
        result.add(num);
    }
}
return Array.from(result);

// 代码优化
 //数组搜索值 复杂度0(n) set Map -.has 复杂度0(1)
 // 两个数组的交集
var intersection = function (nums1, nums2) {
    
    
    const result = new Set();
    const set = new Set();
    for (num of nums2) {
    
    

        if (set.has(nums)) {
    
    
            result.add(num);
        }
    }

}
return Array.from(result);

11 甲板上的战舰

给定一个二维的甲板 请计算其中有多少艘战舰 战舰使用x表示 空位用“。”表示 需要遵守以下规则
1给你一个有效的甲板 仅有战舰或者空位组成
2、战舰只能水平或者垂直放置 也就是说只能由1xN(1行,n列)组成 或者Nx1(N行 1列)组成 其中N可以是任意大小
3、两艘战舰之间至少有一个水平或垂直的空位分隔,即没有相邻的战舰。
在这里插入图片描述
在这里插入图片描述
解题思路:
使用沉没 小岛个数问题 判断是x之后就记录 然后沉没 防止重复

// 甲板上的战舰
var countBattleships = function (board){
    
    
    let result = 0;
    //循环二维数组
    for (let row=0;row<board.length;row++){
    
    
        for(let col = 0;col<board[0].length;col++){
    
    
            //判断如果等于x 周围的也等于x 就继续  否则跳出循环
            if(board[row][col] === "X"){
    
    
                if(row>0&& board[row-1][col] === "X"){
    
    
                    continue;
                }
                if(col>0 && board[row][col-1] === "X"){
    
    
                    continue;
                }
            }
            result ++;
        }
    }
}

12 两数相加 ii

给定两个非空链表来代表两个非负整数,数字最高位位于链表的开始位置 他们的每个节点只存储一位数 除了数字0之外不会有0开头的
在这里插入图片描述
这道题要注意的是链表的长度可能不一致 所以我们不能直接从头开始相加 应该从尾部相加
解题思路:
先反转 在相加 然后再反转
利用栈 现金后出的特点 使用两个栈 依次压入 全部压入之后再取出
代码实现:

// 两链表相加
var addTowNumbers = function (l1,l2){
    
    
    const stack1 = [],stack2=[];
    while(l1 !==null){
    
    
        //判断不为1就往里面压入
        stack1.push(l1.val);
        l1=l1.next;
    }
    while(l2 !== null){
    
    
        stack2.push(l2.val);
        l2= l2.next;
    }
    let carry = 0,curr = null;
    while(stack.length !== 0 || stack2.length !== 0){
    
    
        let sum = 0;
        if(stack1.length !== 0){
    
    
            sum += stack1.pop();
        }
        //进位
        sum += carry;
        // 处理新链表中节点问题
        const node = newListNode(sum % 10);
        carry = Math.floor(sum / 10);
        //新的节点放到链的头部 
        node.next = curr;
        curr = node ;
    }
    if(carry !== 0){
    
    
        const node  = new ListNode(carry);
        node.next = curr;
        curr = node ;
    }
    return curr;
}

13、斐波那契数列

题目描述:(动态规划)
在这里插入图片描述
后一个数等于前两个数的和
解题思路:
动态规划主要有recursion 和memoizatipn 递归和记忆化
记忆化就是在递归的基础上代入一些递归后的值 就不需要重复去计算了 这就是动态规划的核心
递归的重点在于找到终止条件 否则就会一直进行下去
新开辟一个数组放计算的记忆计算存放的值

代码实现:

//递归加记忆解法
var fib = function (N){
    
    
    if(N <= 1){
    
    
        return N;
    }
    // 初始化缓存数组 1和2是已知的
    const cache = [];
    cache[0] = 0;
    cache[1] = 1;
    // 写记忆函数 要注意cache里面有没有存在这个数组 有的话就直接用 没有的话就调用递归
    function memoize(number){
    
    
        // 如果cache里面有number 就直接return出去
        if(cache[number]  !== undefined){
    
    
            return cache[number];
        }
        // 否则否则的话就递归计算
        cache[number] = memoize(number -1)+ memoize  (number - 2);
        return cache[number];
    }
    const result = memoize(N);
    return result;
}

解法2:从1往后填数组 空间复杂度有优化(有可能)

// 第二种解法是把cache这个数组全部填好 用的时候直接用
// 从前往后一个一个算直到N
var fib = function (N){
    
    
    if(N <= 1){
    
    
        return N;
    }
    cache [0] = 0;
    cache[1]= 1;
    //循环从第一个开始算 加到最后一个
    for(let l=2;i<=N;i++){
    
    
        cache[i] = cache[i-1] + cache[i-2];
    }
    return cache[N];
}

解法3:

// 第三种解法是不断更新N-1和N-2
// prev1代表N-1  prev2代表N-2
var fib = function (N){
    
    
    if(N <=1){
    
    
        return N;
    }
    let prev2 = 0;
    let prev1 = 1;
    let result = 0;//这里可以初始化为0
    for(let i = 2; i<= N;i++){
    
    
        result = prev1 + prev2;
        //把1和2更新
        prev2 = prev1;
        prev1 = result;
        
    }
    return result;
}

14、验证回文字符串||

描述:给定一个非空字符串 最多删除一个字符 判断是否能成为回文字符串
在这里插入图片描述
注意:字符串只包含总a-z的小写字母 字符串最大的长度为50000
思路分析:
自己:在基础回文串的前提下 两个指针 如果遇到不相同的字符 (回文串是直接返回false) 这道题就删除这个数继续 回文验证 直到最后
要注意的几个点是 删除只能进行一次 如果第二次出现不一样的话直接放回false(最后好像行不通)
老毕:当i不等于j的时候 需要判断i+1是否等于j 或者i是否等于j-1 任意一种情况是true的话就可以继续做
代码实现:

//验证回文字符串 这里单独提出来 后面用到
var validPalindrome = function(s){
    
    
    function isPalindrome(left,right){
    
    
        while(left<right){
    
    
            if(s[left] !== s[right]){
    
    
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
    let left = 0,right = s.length-1;
    while(left<right){
    
    
        //如果两者不相等的情况 看一下是不是下面这两种情况
        if(s[left] !== s[right]){
    
    
            const result = isPalindrome(left+1,right) || isPalindrome(left ,right-1)
            return result;

        }
        left ++;
        right --;
    }
    return true;
}

15、岛屿最大面积

描述:给定一个包含了一些0和1的非空二维数组grid
一个岛屿是由一些相邻的1(代表土地)构成组合 这里的相邻要求两个1必须在水平或者竖直的方向上相邻 可以假设给定的四个边缘都被0包围 找到给定二维数组中最大的岛屿面积(如果没有岛屿 返回面积为0)
注:这里是要找出最大面积的一个岛 之前是找出几个岛

解题思路:
设置一个值:每次沉没的时候 就加一 然后下次出现新的小岛的时候 如果数字这个值小 继续做 如果比这个值大更新这个值; 所有值都沉没之后 放回这个最大值
代码实现:

//岛屿最大面积
var maxAreaOfIsland = function (grid){
    
    
    let result = 0;
    for (let row = 0;row <grid.length; row++){
    
    
        for(let col=0;col<grid[0].length;col++){
    
    
            // 如果等于1的h话把他沉没然后加入count中并比较
            if(grid[row][col] === 1){
    
    
                const count = dfs(row,col);
                result = Math.max(result,count)
            }
        }
    }
    function dfs(row,col){
    
    
        //如果是这样的话 直接返回 超出边界了
        if(row<0 || row>grid.length || col<0 || col>= grid[0].length || grid [row][col] === 0){
    
    
            retrun ;
        }
        grid[row][col] = 0;
        let count = 1; //初始化为1
        // 往四周去递归这个函数 如果存在的话就去count+
        count += dfs(row-1,col);
        count += dfs(row+1,col);
        count += dfs(row ,col-1);
        count += dfs(row ,col+1);
        return count ;
    }
    return result;
}

16、二分查找 Binary Search

描述:给定一个数组 从小到大排序好了 找到一个数 然后返回所在的index 否则返回-1
乱序的数组没办法使用二分搜索
在这里插入图片描述
解题思路:利用数组排序好的特点 直接把数组分类两段判断这个数和我们要找的数大小 如果是小于我们的数左边放弃 只看右边 在进行二分查找

1、left= 0 right = length-1, mid = left+(rigth -left )/2 这样写是防止出现最大值溢出
放回mid 如果小于target left= mid+1(砍掉左半边)如果大于target right= mid-1 (砍掉右边)如果大于target right= mid-1(砍掉右半边)
3、如果while循环结束后没有找到target 返回-1

一些特殊情况:

边界问题的处理上

代码实现:

// 二分搜索 
var search = function (nums,target){
    
    
    let left = 0,right = nums.length -1;
    while(left <= right){
    
    
        //计算出中间值
        mid = Math.floor(left +(right -left)/2);
        //如果相等 直接放回
        if(nums[mid] === target){
    
    
            return mid;
            //小于丢弃右边 大于丢弃左边
        }else if(target<nums[mid]){
    
    
            right = mid -1;
        } else {
    
    
            left = mid +1;
        }
    }
    return -1;
}

17、图像渲染

题目描述:
有一副以二维整数数组表示的图画 每一个整数表示该图画的像素值大小 数值在0到65535之间 给定一个坐标 (sr,sc)表示图线渲染开始的像素值(行,列)和一个新的颜色值newColor 让你重新上色这幅图画 为了完成上色工作 从初始坐标开始 记录初始坐标的上下左右四个方向上像素值与初始坐标相同的相连像素点 接着在记录这四个方向上符合条件的像素点与他们对应的四个方向上像素值与初始坐标相同的相连像素点 重复该过程 将所有有记录的像素点的颜色值改为新的颜色值
最后返回经过上色渲染后的图像
在这里插入图片描述
一看这题目就比较绕 接下来好好分析一下:看这个图比较好理解
输出前后:加粗样式
跟战舰那道题差不多
首先得到一个点之后像周围扩散 看和这个点是不是一样的 如果是的话就改变颜色 (从1变到2)如果不是的话就继续下一个点
最后返回的应该是整个数组
代码实现:

// 图像渲染
var floodFill = function (image, sr, sc, newColor) {
    
    
    //如果给定的这个颜色为要改变的颜色 可以直接返回
    if (image[sr][sc] === newColor) {
    
    
        return image;
    }
    const oldColor = image[sr][sc];
    function dfs(sr, sc) {
    
    
        if (sr < 0 || sr > image.length || sc < 0 sc > image[0].length || image[sr][sc] !== oldColor) {
    
    
            // 这几种情况都不许要操作 直接return 最后是不是给定的颜色
            return;
        }
        //把当前的点改为最新的颜色
        image[sr][sc] = newColor;
        // 上下左右继续执行这个函数
        dfs(sr-1,sc);
        dfs(sr+1,sc);
        dfs(sr ,sc-1);
        dfs(sr,sc+1);
    }
    dfs(sr,sc);
    return image;
}

18、 旋转字符串

给定两个字符串A和B
A的旋转操作就是将A最左边的字符移动到最右边 列如,偌A=“abcde”,在移动一次后的结果是“bcdea”。如果在若干次旋转操作之后 A能变成B 则返回True
在这里插入图片描述
注意:A和B的长度不超过100
在这里插入图片描述
思路:
旋转的次数为s.length-1次 超过的话就重复了
在分析的时候发现旋转多了之后就是重复的 优化之后就可以简写成为两个s的字符串 然后看这个字符串中有没有包含b(直呼nb)
在这里插入图片描述
代码实现:

//旋转字符串
var rotateString = function(A,B){
    
    
    if(A.length !==B.length){
    
    
        return false;
    }
    const str = A + A;
    return str.includes(B);
}

19、矩形重叠

题目描述:矩形以列表[x1,y1,x2,y2]的形式表示 其中(x1,y1)为左下角的坐标 (x2,y2)是右上角的坐标
如果相交的面积为正 则称为两矩形重叠 需要明确的是 只在角或边接触德 两个矩形不构成重叠
给出两个矩阵 判断要他们是否重叠并返回结果 最后返回布尔值
在这里插入图片描述
出现这四种情况说明不相等:
在这里插入图片描述
代码实现:

var isRectangLeOverlap = function(rec1,rec2){
    
    
    if(rec1[2] <= rec2[0] || rec1[0] >= rec2[2] || rec1[1] >= rec2[3] || rec1[3] <= rec2[1]){
    
    
        return false;
    }else{
    
    
        return true;
    }
}

20、比较含退格的字符串

给定S和T两个字符串 当他们分别被输入到空白的文本编辑器后 判断留着是否相等 并返回结果 #代表退格字符 一个#代表一次退格操作(就是删除呗)
注:如果对空文本输入退格字符 文本继续为空
在这里插入图片描述
解题描述:从后往前读 遇到#号的时候记录一下 跳过下一次添加字符 所以需要两个指正,从后往前移动
设定两个数组用来记录退格的次数
1、当在移动中遇到退格时 数组加一
如果当前不是退格 看数组中是否为0 如果不为0则做相应移动 直到数组中未0为止
2、如果不是退格数组也为0 则把两个数组的字符进行比较 如果相同则继续 如果不同就返回false

代码实现:

var  backspaceCompare = function (S,T){
    
    
    let i = S.length -1,
    j = T.length -1;
    //两个数组用来记录原始数组中退格的数量
    let backspaceS = 0;
    let  backspaceT = 0;
    while(i=0 || j>=0){
    
    
        while(i>=0){
    
    
            if(S[i] === "#"){
    
    
                backspaceS++;
                i--;
            }else if(backspaceS > 0){
    
    
                backspaceS --;
                i --;
            }else {
    
    
                break;
            }
        }

        while(j>=0){
    
    
            if(T[j] === "#"){
    
    
                backspaceT++;
                j--;
            }else if(backspaceT > 0){
    
    
                backspaceT --;
                J --;
            }else {
    
    
                break;
            }
        }
        if(S[i] !== T[j]){
    
    
            i++;
            j--;
        }
        return true;
    }
}

21、链表的中间节点

给定一个带有头节点head的非空单链表 返回链表的中间节点
如果有两个中间节点 则返回第二个中间节点
在这里插入图片描述
思路分析:
需要两个指针 一个快指针 一个慢指针
慢指针一次一步 快指针一次两步 当快指针走到最后的时候 慢指针所在的位置就是中间节点 注意先走慢指针
代码实现:

//链表的中间节点
var middleNode = function (head){
    
    
    let slow = head ;
    let fast = head ;
    while(fast !== null && fast.next !== null){
    
    
        slow = slow.next;
        fast = fast.next.next;
    }
    return slow;
}

22 、按奇偶数排序数组

给定一个非负整数数组A 返回一个数组,在该数组中 A的所有耦元素之后跟着所有的奇数元素 不能开新的数组 直接在当前数组操作
以返回任何满足此条件的数组作为答案
在这里插入图片描述

思路分析:
使用双指针i和j 最开始一个 最后一个 如果是奇数放到后面 偶数放到前面
具体操作:
1、i奇数 j偶数 两者交换
2、i偶数 j偶数 i++ j不动
3、i奇数 j奇数 i不动 j–
4、i奇数 j偶数 i++ j–

代码实现:

//  按奇偶排序数组
var sorArrayByParity = function (A){
    
    
    let i = 0, j = A.length -1;
    while(i<j){
    
    
        if(A[i]%2 === 1 && A[j]%2 === 0){
    
    
            [A[i],A[j] = [A[j] ,A[i]];
            i++;
            j++;
        }else if(A[i]%2 === 0 && A[j]%2 === 0 ){
    
    
            i++;
        }else if(A[i]%2 === 0 && A[j]%2 === 1 ){
    
    
            i++;
            j--;
        }else{
    
    
            j--;
        }
    }
    return A;
}

23、按照奇偶排序数组2

描述:给定一个非负整数数组A A中一半整数是偶数。对数组进行排序,以便当A[i]是奇数的时候 i也是奇数 a[i] 是偶数的时候 i也是偶数 其实就是一个奇数一个偶数的排列
在这里插入图片描述
思路:依然是两个指针 I 和j i第一个 j第二个
i每次跳两格 j每次也跳两格 就保证每次 i的位置都是偶数,
如果i不是偶数 就停下看 j
就看当前的j 如果j是偶数 就交换 如果j
不是偶数 j继续跳两格 直到j是偶数进行交换
交换完成之后在移动i
只要i走到头 那么也就结束了

代码实现:

var sortArrayByParityII = function(A){
    
    
    let j=1;
    for(let i=0;i<A.length; i+=2){
    
    
        if(A[i]%2 === 1){
    
    
            while(A[j]%2 === 1 && j<A.length){
    
    
                j+=2;
            }
            [A[i],A[j]] = [A[j],A[i]];
        }
    }
    return A;
}

看到这里终于把50多节算法课学习完成了 也算是一个算法的初级入门 确实对一些算法的解决方法有一定的认识 接下来就准备继续到力扣刷题 刷一个月左右 坚持呀
在学习听课的过程中发现了一些不太懂的知识点 后面也会慢慢总结出来
下面就是开始重学前端系列

猜你喜欢

转载自blog.csdn.net/weixin_44865458/article/details/121201780