当前位置: 首页 > news >正文

算法题笔记

哈希

两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。

你可以按任意顺序返回答案。

class Solution {public int[] twoSum(int[] nums, int target) {Map<Integer, Integer> hashtable = new HashMap<Integer, Integer>();for (int i = 0; i < nums.length; ++i) {if (hashtable.containsKey(target - nums[i])) {return new int[]{hashtable.get(target - nums[i]), i};}hashtable.put(nums[i], i);}return new int[0];}
}作者:力扣官方题解
链接:https://leetcode.cn/problems/two-sum/solutions/434597/liang-shu-zhi-he-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

哈希表法有2个特点:

  1. 内存换时间;
  2. 哈希表快速查找;

如果遍历数组,把数放到另一个数组而不是哈希表,数组无法瞬间找到目标值,时间复杂度还是降不下来,内存占用也多了。它们的区别是遍历数由小到大还是由大到小。

双指针

接雨水问题

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 1:

  1. 如果用一个左指针记录坑左边,用右指针往右找试图把坑封住,会遇到封不住但是里面有小坑的情况。比如左指针在最高点,右指针向右就找不到匹配的右高点,但是里面有小坑。
    public int Trap(int[] height) {int p1=0,p2;//p1先找到坑左边,List<int>rains=new List<int>();int rain;while(p2<height.Length){if(nums[p1]>nums[p1+1]){q.Enqueue(p1);p1++;}// if(nums[p1]<=nums[p1+1]){//找一个下坡//     p1++;// }// else{//     p2=p1+1;//     if(nums[p2]<nums[p1]){//         rains.Add(nums[p2]);//         p2++;//     }//     else{//         lower=Math.Min(nums[p1],nums[p2]);//         for(int i=0;i<rains.Count;i++){//             rain+=lower-rains[i];//         }//         rains.Clear();//     }// }}}

  2. 然后回忆起括号匹配的问题,可以用一个队列记录左斜坡,往右找斜坡去匹配,但是大坑套小坑时如果算所有坑的积水,肯定会重复。

两种思路都有漏洞。

滑动窗口

无重复字符的最长子串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长 子串 的长度。

示例 1:

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

示例 2:

输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

示例 3:

输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

难点是这个子串的位置和长度不确定,如果从一个字符开始加,不知道从哪里开始,然后想从整个字符串开始剔除行不行?就从左边开始,字符在右边的子串里有则剔除,一直剔除到abcbb,左边的a无法剔除了,然后从右边剔除,剔除2个b得到结果,好像可以?然后拿例子3测试,左边无法剔除,右边剔除w后无法剔除,得到的wwke是错误结果,说明这个方法有漏洞。就是两边有独特字符,中间有重复字符。

然后又想把所有连着相同的字符之间切开,但是如果相同字符不相邻明显有不行。

然后感觉还是要从一个字符开始“生长”的方法。就想从左开始遇见已有的字符就开始一个新的子串的“生长”,得到一个字符串列表,取长度最长的。这样有什么漏洞吗?这样可能忽略了某些其他分割方式?例如向右生长时再长一个就左边就出现重复字符,但是右边可能存在更长的子串,比如cabcfke,从左往右生长会分成cab、cfke,但是有abcfke更长。所以还是有漏洞。

那如果再从右往左来一次呢?得到2个字符串列表,取其中最大的长度。对于cabcfkemne,从左长是cab、cfkemn、e,最长是6,从右长是mne、abcfke、c,最长是6,但实际最长是abcfkemn,长度8.还是有漏洞。

这个最长子串一定是向左或右加一个就会有重复的。可以把字符串分割成若干有重叠的子串,每个子串无法再延长,然后有一个暴力算法,每个字符都向两边延长,直到有重复,但是延长方式又是个问题,可以左右交替延长,可以只朝一侧,可以左2次右1次,有无数种延长方法。

那如果延长遇到重复时记录一下长度,然后把从重复字符及其另一侧的字符全部丢弃,继续延长呢?然后我们似乎能理解“滑动窗口”是什么意思了。这里每次分割,长度不得不减少时都记录一下长度,然后继续延长。好像没什么问题,然后就写伪代码:

  1. 有一个字符列表,从左侧字符循环;
  2. 用IndexOf判断列表含不含右边字符在不在列表;
  3. if 在 then 同时获得那个重复字符的Index,记录此时的长度,比max大则更新,用RemoveRange移除它及其左边的部分;
  4. 把右边字符加入列表,回到2;
  5. 返回max。但是为了处理从未切割(max=1,未更新过)的情况,要把max和最后字符串的长度取最大值;
  6. 为了把内存一次申请够,就申请和字符串一样长的列表;
public class Solution {public int LengthOfLongestSubstring(string s) {if(s==""){return 0;}List<char>list=new List<char>(s.Length){s[0]};int max=1;for(int i=1;i<s.Length;i++){int index=list.IndexOf(s[i]);if(index!=-1){if(list.Count>max){max=list.Count;}list.RemoveRange(0,index+1);}list.Add(s[i]);}return Math.Max(max,list.Count);//Max为了处理从未切割的情况}
}

官方做法

每次先移除左边一个字符,再用while循环添加右边字符,属于“减一加多”和上面的“减多加一”方法相反,在while循环多次不满足的时候也会出现连续多次减一的情况,一直减到子串里重复的字符被剔除,相当于上面方法RemoveRange的一次性剔除。

不过顺序都是先减后加,因为规则的限制。

class Solution {
public:int lengthOfLongestSubstring(string s) {// 哈希集合,记录每个字符是否出现过unordered_set<char> occ;int n = s.size();// 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动int rk = -1, ans = 0;// 枚举左指针的位置,初始值隐性地表示为 -1for (int i = 0; i < n; ++i) {if (i != 0) {// 左指针向右移动一格,移除一个字符occ.erase(s[i - 1]);}while (rk + 1 < n && !occ.count(s[rk + 1])) {// 不断地移动右指针occ.insert(s[rk + 1]);++rk;}// 第 i 到 rk 个字符是一个极长的无重复字符子串ans = max(ans, rk - i + 1);}return ans;}
};作者:力扣官方题解
链接:https://leetcode.cn/problems/longest-substring-without-repeating-characters/solutions/227999/wu-zhong-fu-zi-fu-de-zui-chang-zi-chuan-by-leetc-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

动态规划

下降路径最小和



931. 下降路径最小和 - 力扣(LeetCode)

思考过程:由“正方形”条件发现=>到达最后一行前不可能走过所有列=> 去掉最后一行一定能找到一个没走过的列,且这个列一定是最左或最右列=>dp[i-1]的解路线就是dp[i]去掉最后一行和最左或最右列的解

http://www.dtcms.com/a/328651.html

相关文章:

  • Java连接MySQL数据库
  • Socket 套接字常用方法
  • Java多源AI接口融合框架:动态模型切换与智能路由实战
  • pybind11绑定C++项目心得
  • Sentinel 和 Hystrix
  • MySQL 存储过程终止执行的方法
  • 力扣热题100------279.完全平方数
  • XGBoost 的适用场景以及与 CNN、LSTM 的区别
  • AQS的原理与ReentrantLock的关系
  • 基于Rocky Linux 9的容器化部署方案,使用Alpine镜像实现轻量化
  • 企业高性能web服务器(3)
  • Linux学习-应用软件编程(文件IO)
  • 【科研绘图系列】R语言绘制特定区域颜色标记散点图
  • Pytest项目_day13(usefixture方法、params、ids)
  • 【不动依赖】Kali Linux 2025.2 中安装mongosh
  • 【数据结构】二叉树详细解析
  • 安路Anlogic FPGA下载器的驱动安装与测试教程
  • C++联合体的定义
  • 数据结构 二叉树(2)堆
  • 带宽受限信道下的数据传输速率计算:有噪声与无噪声场景
  • C++方向知识汇总(四)
  • PyCATIA高级建模技术:等距平面、点云重命名与棱柱体创建的工业级实现
  • 基于Java与Vue搭建的供应商询报价管理系统,实现询价、报价、比价全流程管理,功能完备,提供完整可运行源码
  • Python训练营打卡Day30-文件的规范拆分和写法
  • 树与二叉树
  • NY198NY203美光固态闪存NY215NY216
  • 串口通信学习
  • Xshell远程连接Ubuntu 24.04.2 LTS虚拟机
  • 模型 霍特林法则
  • 自动驾驶 HIL 测试:构建 “以假乱真” 的实时数据注入系统