这是我参与8月更文挑战的第11天,活动详情查看:8月更文挑战
题目描述:
219. 存在重复元素 II - 力扣(LeetCode) (leetcode-cn.com)
给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的 绝对值 至多为 k。
示例一
输入: nums = [1,2,3,1], k = 3
输出: true
示例二
输入: nums = [1,0,1,1], k = 1
输出: true
示例三
输入: nums = [1,2,3,1,2,3], k = 2
输出: false
思路分析
用散列表来维护一个 k 大小的滑动窗口。
我们来把题目的描述转换下
找到 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的 绝对值 至多为 k。
⬇⬇⬇
在一个大小为 k 的区间里,看下存不存在两个数相同。
这个 大小为 k 的区间 我们有好几种方法去实现。 这个区间我们可以理解为 算法中常见的 "窗口"。
假设 k =3 我们就有一个长度为3的这么一个窗口,我们从最左边一直往右移,去看这个窗口(框里)有没有相同的数字,这样就很好理解了吧。
再生动点,可以参考下这个老哥的动画
AC代码
class Solution {
fun containsNearbyDuplicate(nums: IntArray, k: Int): Boolean {
val window = mutableSetOf<Int>()
for (i in 0..nums.lastIndex) {
if (!window.add(nums[i])) {
return true
}
if(window.size > k) {
window.remove(nums[i - k])
}
}
return false
}
}
线性搜索
官方是这么称呼的,思路就是遍历,然后将每个元素与它之前的 k 个元素中比较查看它们是否相等。
代码就略过了。
总结
以前断断续续也看过一些算法书,里面的窗口也是挺眼熟,这是在我的题解中第一次出现窗口这个字眼,其实抛开看似这么专业的称呼,我们就以实际例子(窗口就是一个框,滑动就是框去套,平移)去理解就非常好理解了。
所以还是实践出真知,很多理论都是实践出来的,很多模板,设计模式也都是总结抽象出来的。
参考
存在重复元素 II - 存在重复元素 II - 力扣(LeetCode) (leetcode-cn.com)
画解算法:219. 存在重复元素 II - 存在重复元素 II - 力扣(LeetCode) (leetcode-cn.com)