有序集合的一些感想

前言
有序集合的思想本质上是二分的思想,即给定一个值(查找值),在一个有序集合中找出()(第一个)满足条件的的元素(即目标元素)。但是很多时候集合是无序的,因此我们需要维护一个有序集合来找出目标元素。比如,我们要想在一个无序的数组中找出一个与查找值相等的元素,则我们会联想到将当前数组排序,即维护一个有序集合,在通过二分的思想查找目标元素,此时时间复杂度从依次遍历的O(n)降低到了O(nlogn),而这也是我们引入有序集合的原因之一,即提高时间上的效率。
为什么需要有序集合

现在我们已一个无序的数组开始下面的论述。

假如我们给定一个确切的值,我们可以从数组左端开始遍历,然后维护一个有序集合,当前遍历元素插入这个集合,然后我们每次在有序集合里面查找目标值。我们也能够完成前言所说的任务。当然这是没必要的,而且会浪费多余的时间在维护当前这个集合上,而这个其实就是有序集合的使用场景。我们想一想为什么上面这个过程,有序集合没用,其实我们观察可以知道,我们的查找值是一直未变的,但如果查找值与我们当前遍历的值息息相关,即会影响我们每次查找的条件,那么我们很有必要使用有序集合的思想解决问题了。

例1:

给定一个整数数组,判断是否存在重复元素。

我们设遍历数组的指针j,j前已经遍历的数组元素我们统一加入有序集合中,假设当前遍历到a[j],我们就在这个有序集合中查找满足条件a==a[j]的元素,如果查找到,证明该数组存在重复元素,若没查找到,我们将当前a[j]加入有序集合,并开始遍历下一元素。需要注意的是:过程中我们一般都是将当前元素作为查找值先判断,判断完再加入集合(如果需要的话)。

例2:

给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的 绝对值 至多为 k。

有序集合+滑动窗口。这个例子换句话说是限制了我们有序集合的大小为k,而每次当要超过这个范围时,我们总是丢弃最先加入的元素,而这恰恰与滑动窗口的思想不谋而合。因此这里我们只需保证有序集合满足上述维护规则即可。

例3:

给你一个整数数组 nums 和两个整数 k 和 t 。请你判断是否存在 两个不同下标 i 和 j,使得 abs(nums[i] - nums[j]) <= t ,同时又满足 abs(i - j) <= k 。

这个例子中我们依旧使用例2的两个思想,因为这里只是查找条件发生了改变。这里我们查找的元素要落在[x - t, x + t]范围内(x为当前遍历的元素)。注意到这里的下界为x-t,因此我们可以通过二分(进阶)的思想,在当前有序集合中查找第一个满足x-t≤的元素y,如果y同时满足≤x+t,则证明我们已找到目标元素。若y不满足,则证明有序集合中没有目标元素。

有序集合和哈希
在例2和例3中,我们其实还可能优化时间复杂度。例2我们可以通过将有序集合中的每个值都映射到一个哈希值上,从而在O(1)时间内查找到结果。例3中,我们可以采用桶排序的思想,将桶大小设置为t+1,而有序集合其实也就是桶,每次我们查看当前元素应在的桶内是否已有其他元素,或者上一个桶或下一个桶满足条件中的不等式,这三者其一发生则证明目标元素的存在。(与本文无关但与这个解法有关的PS:每个时刻桶内一定只有一个元素,因为当有两个元素时,一定在之前就已经返回结果了,所以这里桶可以用map实现),而桶排序实质上就是哈希。

总结
从上面我们可以看出有序集合可以用数组或哈希实现,有序集合可以与滑动窗口搭配使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值