1. 滑动窗口
因为只知道是字符,所以用hash表(unordered_map)来判重。
hash表中记录字符位置,当遇到重复时,跳过记录的该字符的位置到达下一个位置。
时间复杂度O(n)
,空间复杂度O(字符数)
(hash表占用)
1 | class Solution { |
因为只知道是字符,所以用hash表(unordered_map)来判重。
hash表中记录字符位置,当遇到重复时,跳过记录的该字符的位置到达下一个位置。
时间复杂度O(n)
,空间复杂度O(字符数)
(hash表占用)
1 | class Solution { |
1 | /** |
set
:find()
和count()
对数级别复杂度,插入insert()
在给定迭代器作为位置的情况下是O(1)
,不给则是对数级别复杂度。unordered_set
:find()
和count()
平均是O(1)
,最坏O(n)
(hash函数太差了),插入insert()
同查找。
1 | class Solution { |
如果有结果,那么就好像是一条链一样。
如果没结果,不是快乐数,则代表有循环,也就可以转换成环形链表来做,快慢指针重合时代表不是快乐数。
这样就避免了set一直存数。
时间上跟unordered_set一样都是O(logn)
,空间更优,是O(1)
。
二分,然后根据左右大小关系判断是上升还是下降,选择不同部分继续二分就好了。
本来打算一次二分做的,不过发现当nums[mid] > target
时,两侧部分都需要进行二分。
所以还是先二分找到分界点,然后再二分左侧和右侧吧,最多是3次二分。
1 | /** |
异或^:相同为0,不同为1.
假如只有一个不成对出现的数字,则基于这个性质,成对出现的数字异或起来得到全0,再异或上这个数字,结果就是这个数字,所以只需要全部异或起来就可以了。(妙啊
如果有两个不成对出现的数字a, b,则全部异或得到a^b,并不是想要的答案。
我们可以想到,如果把数据分为两组,1组有a和一部分成对的数据,2组有b和剩余部分成对的数据,则1组全部异或得到a,2组全部异或得到b。
现在的问题是如何分为两组。
a^b得到的结果中,有的位是0,有的位是1,而1的位说明a和b在该位上不相等。
所以可以取任意一个为1的位,将该位为1的数据分到1组,该位为0的数据分到2组。
这样1和2一定可以分开。
而由于成对出现的数据在同一位上一定是相同的,所以也可以被分到同一个组中,这样分组就完成了。
实际上也并不需要显式地分成两部分。
只要在循环的时候判断某一位是01,然后对应的异或到相应位置就可以了。
1 | class Solution { |
通过左和中的大小关系判断是升序还是中间旋转了。
时间O(logn)
,空间O(1)
。
1 | class Solution { |
每次比较k个链表,这样每合并出一个节点,就需要O(k^2)
的时间。所以此处可以优化一下,使用堆就可以以O(klogk)
的时间得到最小值,花费最大O(k)
空间。
为了获得堆顶弹出的元素来自的链表,所以还需要一起记录一下,可以用pair。
插入一次需要O(logk)
的时间,一共nk个元素都需要进出堆,所以时间复杂度为O(nklogk)
。
1 | /** |
因为回溯是可以画出一棵回溯树的,所以光第一层调用dfs就要n次,而每次dfs还要层层深入,所以复杂度是很高的。
leetcode官方题解上分析出(组合数的加法),时间复杂度是 O(n*n!)
,空间复杂度由于结果数组,所以是 O(n*n!)
,如果不考虑结果数组的话,则是 O(n)
。
1 | class Solution { |
归并排序的讲解见每日1题-912,归并排序的一个用途之一就是求解逆序对.
归并排序在每次合并的时候,如果是将右半部分的一个元素移入到合并后的数组中,则说明左侧数组中剩下部分的元素都大于右半部分的这个元素。
这样一下子就得到了好多逆序对。
只需要对原有的归并排序添加count即可。
时间复杂度O(nlogn)
,空间复杂度O(n)
,均同于归并排序。
1 | class Solution { |
时间O(n)
,空间O(1)
,不过要是能继续把公式往下推的话,可能会有时间O(1)
吧。
1 | class Solution { |