🤠代码随想录(leetcode)

type
status
date
slug
summary
tags
category
icon
password

📝 力扣

 
😀
此篇为leetcode算法的基础 方法论: 限时+先写最简单的+调试 包括 1. 一次遍历(学习中)尽可能的理解和记住知识 2. 手撕才是key point 3. 代码随想录 https://www.bilibili.com/video/BV1cy4y167mM/ 4. 展开阅读 展开阅读 展开阅读

双向指针

😇
啥时候用: 数组
解法: while(left<right) 什么条件++ — 有些可能需要先排序
两数之和
核心: 递增,只对应唯一的答案,不可以重复使用
三数之和
排序然后写出两数之和
记得循环要包多少,push完后还要++
while (nums[left] == nums[left - 1] && right > left)
特例: nums[i]>0 只有相等++之后判断与原值是否一样,以及开头
二分搜索法
核心: 更新左右端点
注意: 坚持对区间的定义才能搞请while(left≤right) right=mid-1
有序数组的平方
核心: 有负数存在,所以最小数一定在中间
注意: 双指针
四数之和
  1. while(nums[left-1]==nums[left] &&)
  1. left++; 在搞定后
  1. if(j>=2 && nums[j-1]==nums[j]&& j != i + 1)
  1. 越界了 [1000000000,1000000000,1000000000,1000000000]
  1. 自己强转会比系统强转快
其他
344.反转字符串: 双向指针交换位置
KMP算法
  1. 字符串匹配的问题 找一模一样的子串
    1. 最接近的三数之和
      1. ???
    1. 统计和小于目标的下标对数目
      1. cnt += right - left;
    1. 有效三角形的个数
      1. 有三个非负整数,如果小的两个的和大于第三个,那它一定能组成三角形
    1. 存最多的雨水
      1. 去掉长边,面积一定变小,尽量在一次循环中处理掉更多的数据
    1. 接雨水:
      1. 两个O(n)的做法,两数组: 黑箱子也看成雨水,高度差间有透明玻璃
      2. 不创建数组的做法: 双指针,利用透明玻璃一定越来越高的原理

    同向指针其他

    😇
    啥时候用: 数组
    解法: slow fast
    1. 子数组子串
    1. 乘积小于k的子数组(713):
    1. 无重复字符的最长子串: 滑动窗口最后都是要检测的 hashset 还不如vector{128,0}
    1. 长度最小的子数组
      1. 正数性质,滑动窗口到底的for循环
    1. 乘积小于 K 的子数组
    1. 无重复字符的最长子串
    1. 最大连续1的个数 III
    1. 替换子串得到平衡字符串
    1. 将 x 减到 0 的最小操作数

    快慢指针

    😇
    啥时候用: 数组、链表
    解法: slow fast
    移除元素
    核心: 双指针解决,快指针赋值给慢支针跳过元素
    注意: erase的时间复杂度是O(n),
    中间节点
    核心: 快指针走两步伐,慢走一步
    环形节点
    1. 快指针走两步,满指针走一步,那么环内,相对速度为+1,则一定会相遇
    1. while(fast!= nullptr && fast->next!=nullptr)
    1. if(slow == fast)
    环形链表2
    1. 找入口就是相遇的那点看是 return nullptr;
    1. 需要注意顺序问题 if(head==slow) 与 head=head->next;
    notion image
    重排链表(太秀了: 寻找链表中点 + 链表逆序 + 合并链表)
    1. 我们先用快慢指针找到链表的中点,然后将链表的后半部分反转,最后将左右两个链表合并
    1. 寻找链表中点 + 链表逆序 + 合并链表)
    回文链表
    1. 快慢指针找
    1. 比较,然后恢复
     
    1. K 个一组翻转链表
    1. 两两交换链表中的节点
    1. 两数相加 II
     
    1. 反转链表II
      1. 反转中间任意一段
      2. 第一个节点前面加一个哨兵节点
      3. left right 是
      4. notion image

    哈希表

    😇
    啥时候用: 判断一个元素是否出现过
    数组unordered_map<char, int> dic;
    解法: set map
    set与muti-set 底层红黑树: 取值慢
    有效的字母异位词
    1. 哈希表: 一次性为两个数组,用数组是因为下标可控
    1. 3层循环,有的话就++,无的话就--,最后看是否有非0
      两个数组的交集
      1. 学习set的用法
       
       
      两数之和
      存遍历过的元素
      四数相加
      1. 下标不可控,要统计出现的次数
      1. 分组 2(a+b) 2 (0 - c - d)在不在map中
      1. 到了其实应该加上 value 的值(因为没有去重)

      栈与队列

      😇
      啥时候用: std::stackpop()函数并不返回任何值,它只是从栈中移除栈顶元素
      栈实现队列: 两个栈
      队列实现栈: 一个队列 123 弹出3 则重新把12加到3后面
       
      删除字符串中的所有相邻重复项
      string有stack的特性
      字符串拼接用加法
       
      逆波兰表达式求值
      遇到符号取两个元素,遇到数字放进去
      数的后序遍历
      stack<int>会比stack<string>好
      std::stoi 与 std::to_string atoi
      notion image
      滑动窗口最大值
      优先队列通过大小顶堆实现: 顺序变了,无法pop
      单调队列:维护出口值一定是最大的 ,push进来的元素比前面大。则弹出所有前面的元素。 本质上是
      前 K 个高频元素
      数字: 出现的频次,把频次排序,所以用map非常的合适 [数字: 频次]
      前k个就好: 大小顶堆,将快排的nlogn 变为nlogk: n为map中个数,大小顶堆每加入一个元素,调整时间复杂度是logk
      而且要用小顶堆,使得树一直是k个节点,每加入一个,淘汰最小的

      递归

      验证二叉搜索树
      1. 区间的思想
      1. LONG_MIN, LONG_MAX
      1. 或者用,
        1. 二叉搜索树——递增序列——做节点的值<节点的树<有节点的值——一定比上个节点值大,判断所有相邻的元素
        2. 照递归左子树访问节点值,节点值,再递归右子树这样的顺序去遍历 一定是递增序列
        3. //函数的定义: 节点值是不是比上个节点值大
        4. 其实就是中序遍历: 递归 处理 递归
      遍历 非递归遍历 非递归遍历-中序 层序遍历(广搜优先搜索) 翻转二叉树 对称二叉树 二叉树的最大深度 二叉树的最小深度 完全二叉树节点的数量 平衡二叉树 二叉树的所有路径 左叶子之和 二叉树:14.找左下角的值 二叉树:15. 路径总和 二叉树:16.从中序与后序遍历序列构造二叉树 二叉树:17.最大二叉树 二叉树:18.合并二叉树 二叉树:19.二叉搜索树中的搜索 二叉树:20.验证二叉搜索树 21:56 二叉树:21.二叉搜索树的最小绝对差 11:53 二叉树:22.二叉搜索树中的众数 21:56 二叉树:23. 二叉树的最近公共祖先 19:03 二叉树:24. 二叉搜索树的最近公共祖先 15:34 二叉树:25.二叉搜索树中的插入操作 10:57 二叉树:26.删除二叉搜索树中的节点 26:23 二叉树:27. 修剪二叉搜索树 19:25 二叉树:28.将有序数组转换为二叉搜索树 14:57 二叉树:29.把二叉搜索树转换为累加树

      回溯

      😇
      啥时候用: for循环用不好的时候
      回溯搜索是暴力搜索: 本质是嵌套for循环,for里面又有递归
      树的广度是集合大小,树的深度是递归的深度,一般返回void
      解决的问题:组合问题,切割,集合的子集排列(强调顺序),棋盘(N皇后,解数独)
      模板:参数并不是一次性给你的那个的
      组合
      组合 + 剪枝 ( 叶子节点为条件,)
      1. 如果是50层的话,for写个50层,不现实
      1. startIdex的存在会让他很方便的传入数组
        1. 图画出来就懂了 //每一层相当于做了一个分发
          1. 若剩余的元素小于需要的k,剪掉
          2. 一个小椭圆是一个遍历,遍历从index开始
          3. notion image
        1. 剪枝,一些没必要发
          1. notion image
        和为n 组合总和 III
        notion image
        电话号码的字母组合
         
        😇
        啥时候用: for循环用不好的时候
        组合总和
        notion image
         
        合总和 II
        notion image
         
        N皇后 太屌了
        notion image

        动态规划

        规划基础 背包问题 打家劫舍 股票问题
        区间dp 概率dp 不用
        dp数组的定义与下标含义 dp如何初始化 遍历顺序 打印dp数组
        斐波那契数,。。
        输入n,有一个个推,dp[i] 上一个或者两个状态
        爬楼梯
        本质是在找规律
        使用最小花费爬楼梯
        跳出去了才要加cost
        dp[i] = min{dp[i-1] + cost[i-1],dp[i-2] + cost[i-2]}
        初始化: dp[0] 与 dp[1]就可以,不需要全部初始化为
        notion image
        不同路径
        本质是在找规律: 注意mxn
        不同路径 II
        初始化不同
        整数拆分
        dp[i] 对 i 拆分,得到最大的成绩
        dp[i] = max(dp[i], j * dp[i-j], j * (i-j))
        不同的二叉搜索树
         
        01背包问题
        暴力回溯: 2^n
        dp[i][j] 表示背包容量为 j 时,从 0..i 类物品种选取,可以获得的最大价值。
        放不放i:
        notion image
        初始化是最难的:
        notion image
        遍历顺序: 都可以,左上方和正上方 dp如果是以为数组则不行
        notion image
        01背包问题: 1维数组版,滚动数组
        放不放i:
        notion image
        notion image
        顺序最难的: 先物品后背包,倒叙遍历:保证每个物品只被加过一次
        当前dp[j]要使用上一层左侧的dp值,正序覆盖了上一层左侧的dp值,倒叙避免
        分割等和子集
        [1, 5, 11, 5]: 价值是5 重量是5
        target为22/2: dp[target]== target时候则可以
        哪些元素相加等于n/2 即0-1背包,容量为n/2
        最后一块石头的重量
        分成近似可能相等的两堆
        目标和
        分成近似可能相等的两堆
        打家劫舍
        notion image

        贪心算法

        分发饼干
        摆动序列
        1. 首位各算一个摆动 坡度上不加加就好
        1. 什么时候res加1
          1. (prediff > 0 && curdiff < 0) || (prediff < 0 && curdiff > 0)
          2. (prediff == 0 && curdiff < 0) —\
        1. 初始值
          1. prediff(前头有一段)=curdiff=0
          2. result = 1 结尾值
          3. 遍历到倒数第二个数字
        最大子数组的和
        1. 当前连续和为负数的话,不如从新开始
          1. if sum<0: sum=0
        1. 全是负数的时候也很正常
          买卖股票最佳时机II
          1. 收集每天的正利润就好
            跳跃游戏
            1. 最多可以跳几个,但想最后到终点
            1. 思维不要太局限,i<cov cov的范围也是可以变的
            1. 只看覆盖范围有无把终点盖住
            跳跃游戏II
            1. 每一步 尽可能提高覆盖范围
            1. 记录下一步的覆盖范围
              notion image
              K次取反后最大化的数组和
              1. 一定要用完
              1. 策略
                1. 优先对绝对值大的负数优先取反
                2. 剩下的对绝对值最小的正数,消耗完所有的取反
               
              加油站
              1. 走一圈回来
              1. 最关注的是补充消耗后还剩多少油
              1. 避开消耗太多的,求和一下试试,一旦变负数,就都不行的
              1. 只能从i+1开始
              分发糖果
              1. 最少的数量,分高则比前面的小孩给的多
              柠檬水找零

              单调栈

              😇
              一个栈:保证是递增(后面首个比他大)或者递减(后面首个比他小) 啥时候用: 当前元素 左边 或者 右边 第一个 比他大或者小 的元素
              每日温度 O(n^2)
              1. 存下标
              1. 存放过遍历过的元素
              1. 默认赋值为0,那留在栈里面的元素就是全为0
              1. while (temperatures[i] > temperatures[st.top()] && !st.empty()) 错了,先判空
              下一个元素
              1. 结果打下是数组1大大小
              1. 单调栈遍历的是数组2
              1. 默认值-1,找不到更大的元素的话
              1. 其中nums1 是 nums2 的子集
              1. 即与上一题的区别在于: 不用记录每一个
                 
                下一个更大元素 II
                1. 可以将[1,2,1] 首位相连 [1,2,1,1,2,1] 但开辟新数组
                1. 模拟成环的过程中 取余
                   
                  接雨水
                   
                   
                   
                   
                  上一篇
                  代码整洁之道
                  下一篇
                  操作系统基础
                  Loading...
                  文章列表
                  一枚热爱技术与产品的产品经理
                  基本信息
                  薯塔AI
                  产品修炼
                  技术分享
                  编码知识
                  AI相关
                  行业知识