LeetCode 232.用栈实现队列
1 | class MyQueue { |
学习了如何使用栈这种数据结构去模仿队列,想法很巧妙。
LeetCode 225. 用队列实现栈
可以使用两个队列也可以使用一个队列,两个队列的话,一个用于存储,一个用于挪移,使用一个队列的话,需要弹出栈顶元素时,将前面的所有元素poll出然后加到最后一个元素后面即可。
1 | class MyStack { |
LeetCode 232.用栈实现队列
1 | class MyQueue { |
学习了如何使用栈这种数据结构去模仿队列,想法很巧妙。
LeetCode 225. 用队列实现栈
可以使用两个队列也可以使用一个队列,两个队列的话,一个用于存储,一个用于挪移,使用一个队列的话,需要弹出栈顶元素时,将前面的所有元素poll出然后加到最后一个元素后面即可。
1 | class MyStack { |
今天的核心内容在于理解KMP算法,还在努力理解中ing~
LeetCode 28.找出字符串中第一个匹配项的下标
1 | class Solution { |
这是没有学习KMP算法前写的朴素解法。
1 | class Solution { |
经过一番学习后,理解了KMP算法的大体思想,不过这里有一些细节之处可能再写时还要进一步的思考。
在KMP算法的学习中发现这个po主的视频讲解的最好,以上代码参考了https://www.bilibili.com/video/BV1iJ411a7Kb?p=5&vd_source=5d8279a9d134034c9a085489dde3d4ac的思路。
今天的主题是字符串:
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s
的形式给出。
不要给另外的数组分配额外的空间,你必须**原地修改输入数组**、使用 O(1) 的额外空间解决这一问题。
示例 1:
1 | 输入:s = ["h","e","l","l","o"] |
示例 2:
1 | 输入:s = ["H","a","n","n","a","h"] |
提示:
1 <= s.length <= 105
s[i]
都是 ASCII 码表中的可打印字符1 | /* |
给定一个字符串 s
和一个整数 k
,从字符串开头算起,每计数至 2k
个字符,就反转这 2k
字符中的前 k
个字符。
k
个,则将剩余字符全部反转。2k
但大于或等于 k
个,则反转前 k
个字符,其余字符保持原样。示例 1:
1 | 输入:s = "abcdefg", k = 2 |
示例 2:
1 | 输入:s = "abcd", k = 2 |
提示:
1 <= s.length <= 104
s
仅由小写英文组成1 <= k <= 104
1 | class Solution { |
这道题的核心思路很简单,其实就是不停的找到下一个需要反转的子串,反转之,然后重复,直到到达输入字符串的末尾,一开始我写了一个相对复杂的版本,试图通过商和余数去判断。后来看了题解发现其实可以直接通过一个for循环更改序号,并通过对i+k和length-1的最小值进行判断从而将边界case纳入一个循环,挺巧妙的,值得学习。
请实现一个函数,把字符串 s
中的每个空格替换成”%20”。
示例 1:
1 | 输入:s = "We are happy." |
限制:
1 | 0 <= s 的长度 <= 10000 |
1 | public class Solution { |
另一种方式是使用双指针从后向前遍历,虽然没有本质的区别,但是这里记录一下这种数组填充元素的双指针从后遍历填充方法:
1 | //方式二:双指针法 |
给你一个字符串 s
,请你反转字符串中 单词 的顺序。
单词 是由非空格字符组成的字符串。s
中使用至少一个空格将字符串中的 单词 分隔开。
返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。
注意:输入字符串 s
中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
示例 1:
1 | 输入:s = "the sky is blue" |
示例 2:
1 | 输入:s = " hello world " |
示例 3:
1 | 输入:s = "a good example" |
提示:
1 <= s.length <= 104
s
包含英文大小写字母、数字和空格 ' '
s
中 至少存在一个 单词进阶:如果字符串在你使用的编程语言中是一种可变数据类型,请尝试使用 O(1)
额外空间复杂度的 原地 解法。
1 | class Solution { |
如注释所示,把整体任务分解成如上的几步,整体并不复杂,有不同复杂度的各种解法,待后续补充。
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串”abcdefg”和数字2,该函数将返回左旋转两位得到的结果”cdefgab”。
示例 1:
1 | 输入: s = "abcdefg", k = 2 |
示例 2:
1 | 输入: s = "lrloseumgh", k = 6 |
限制:
1 <= k < s.length <= 10000
1 | public class Solution { |
计算一下可知,原来的i位置的元素要到 (i + size - n) % size的位置,知道了坐标关系后就可以很方便的进行计算。
除此之外,还可以先反转前n个元素,然后反转后size - n个元素,然后反转整个字符串即可。
LeetCode 454.四数相加-ii
这道题的如果直接使用循环的话其时间复杂度是O(n^4),所以考虑拆成两部分并使用hashmap cache住一部分的结果,可以把时间复杂度降低到O(n^2)
1 | class Solution { |
LeetCode 383.赎金信
1 | class Solution { |
这道题的难度不高,使用数组或者hashmap都可以,本题因为限定了两个字符串都由小写英文字母组成所以使用数组更节省空间。
LeetCode 15.三数之和
1 | class Solution { |
这道题的核心难度在于去重,也就是说我们不希望有(a,b,c)这样的三元数组后,再有(b,a,c) 或者(c,a,b, 因此,在循环中我们希望始终保持循环下标间的顺序为 i < j < k.
由于对一个已经排序的数组寻找twoSum的问题可以使用双指针相向遍历的方式解决,因此,考虑通过外层循环固定一个元素,然后在内层循环使用双指针。
需要注意的是,对于a的去重需要check a之前的一位元素是否与其相等,如果相等的话跳过这次循环。因为a确定的情况下,bc是固定的,如果不跳过此次循环则会引入重复元组。对于bc而言,去重的原因和操作也是类似的。
LeetCode 18.四数之和
1 | class Solution { |
和三数之和类似,多了一些pruning的判断,以及注意第二层循环j的去重。
LeetCode 242. 有效的字母异位词
Ver1:
1 | public boolean isAnagram(String s, String t) { |
Ver2:
1 | public boolean isAnagram(String s, String t) { |
Ver3:
1 | public boolean isAnagram(String s, String t) { |
这道题的难度不高,使用数组充当哈希表,记录每个字符串中各个字符的数量,但是一些小的细节方面的优化值得注意
进阶问题:如果字符串包含unicode字符怎么办?
可以使用hashmap,以字符为key,字符的数量为value,思路一致
LeetCode 349. 两个数组的交集
1 | class Solution { |
因为本题限制了数组中包含的数字的范围,所以可以使用开两个数组的方法作为哈希表,如果数字范围更大一些,则应该考虑使用set。
LeetCode 202. 快乐数
1 | class Solution { |
这道题还是蛮有意思的,一开始没有想明白结束循环的条件,后来才意识到,无限循环意味着重复出现的n,如此,将其加入set,利用set查询时间复杂度为O(1)的优势进行快速查询,如果数字已经check过,那么结束循环,或者数字为1,结束循环。
LeetCode 1.两数之和
1 | class Solution { |
两数之和用暴力法解决思路还是挺直接的,但是暴力法的复杂度太高了。双重遍历的复杂度为n^2,其原因是,对于每一个正在check的数字,搜寻target-nums[i]的开销太大,考虑使用set将已经check过的数字cache起来,并利用其查询O(1)的优势。
LeetCode.24 两两交换链表中的节点
1 | class Solution { |
LeetCode.19 删除链表的倒数第n个结点
1 | class Solution { |
更新了一种双指针,空间复杂度O(1)的解决方法。
LeetCode.160 相交链表
1 | public class Solution { |
有空间复杂度O(1)的方法
1 | public class Solution { |
LeetCode 142.环形链表
1 | public class Solution { |
LeetCode.203 移除链表元素
1 | /** |
注意链表可能为空,引入哨兵节点处理这种Corner Case即可。
LeetCode.707 设计链表
1 | class ListNode { |
关于链表设计的一些思考
LeetCode.206 反转链表
反转链表的核心在于保存当前指向节点的prev和next节点信息,因此使用一个prev指针和一个temp指针记录下信息,之后只要递归或者循环遍历整个链表即可。
1 | class Solution { |
LeetCode.977 有序数组的平方
1 | /* |
双指针方法的简单应用
LeetCode.209 长度最小的子数组
1 | class Solution { |
注意slowIndex的更新应该使用while循环,更新直到sum<target
LeetCode.59 螺旋矩阵II
1 | class Solution { |
对比了一下我的方法和Carl的方法,我写的这个等于是纯粹模拟行为,感觉思维量更少一点,更straightforward.
LeetCode.54 螺旋矩阵
1 | class Solution { |
这一题的思路和螺旋矩阵II类似,但是注意由于矩阵不是正方形的,每一次循环后要check是否已经完成遍历,避免重复打印。
LeetCode 704. 二分查找
1 | // invirants: |
这道题的重点在于循环不变量的确定以及维护,常见的错误点是开闭区间,循环条件,以及循环中左右index的更新。
LeetCode 27.移除元素
1 | class Solution { |
这道题使用双指针方法可以达到O(n)的时间复杂度,最一开始我写的版本双指针在同侧,后来思考后发现这样多扫描了一些元素,所以在此之上做了一些优化,使用两个指针对向遍历,当二者相遇后停止。
Note:循环条件的设定仍然和开闭区间有关
LeetCode 35.搜索插入位置
题目要求在数组中查找指定元素,若检索到该元素,返回其索引,若不包含此元素,返回其应该被插入的位置的索引。
1 | /* |
上述同时实现了开闭区间的解法。
一开始一直纠结的一个点是,当nums[mid] >= target时,将right更新为mid - 1会把valid的节点移除出区间,后来思考了一段时间,发现按照这样的更新方法,结束循环时,所有的>=target的元素都在right右侧,即[right + 1, ],而所有小于target的元素都在left左侧,而退出循环时,总满足left = right + 1, 则left总是指向第一个满足>=target的元素,故而总是返回left即可。
Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.
1 | $ hexo new "My New Post" |
More info: Writing
1 | $ hexo server |
More info: Server
1 | $ hexo generate |
More info: Generating
1 | $ hexo deploy |
More info: Deployment