剑指Offer&LeetCode:一文详尽寻找/删除/替换重复元素(I)

217. 存在重复元素

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

如果任意一值在数组中出现至少两次,函数返回 true 。如果数组中每个元素都不相同,则返回 false 。

示例 1:
输入: [1,2,3,1]
输出: true

示例 2:
输入: [1,2,3,4]
输出: false

示例 3:
输入: [1,1,1,3,3,4,3,2,4,2]
输出: true

解题思路:

  1. 先排序,然后比较相邻两个数即可,若存在相等的数,返回True,不存在返回False,时间复杂度为O(nlog(n))
  2. 使用哈希表

方法1:代码实现:

  • C++:
class Solution {
public:
    bool containsDuplicate(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        for(int i=1;i<nums.size();i++)
        {
            if(nums[i]==nums[i-1])
                return true;
        } 
        return false;

    }
};

方法二:哈希表实现:

  • Python:
class Solution:
    def containsDuplicate(self, nums: List[int]) -> bool:
        #如果数组的长度大于哈希表(里面含有的不同元素个数)的长度,则返回True,否则,返回false
         return len(nums) > len(set(nums))
219 存在重复元素 II

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

示例 1:
输入: nums = [1,2,3,1], k = 3
输出: true

示例 2:
输入: nums = [1,0,1,1], k = 1
输出: true

示例 3:
输入: nums = [1,2,3,1,2,3], k = 2
输出: false

解题思路:哈希表的方法

  1. 维护一个哈希表,里面始终最多包含 k 个元素,当出现重复值时则说明在 k 距离内存在重复元素
  2. 每次遍历一个元素则将其加入哈希表中,如果哈希表的大小大于 k,则移除最前面的数字
  3. 时间复杂度:O(n),n为数组长度
  • Python
class Solution:
    def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool:
        #字典保存键值对
        dct = {}
        for i in range(len(nums)):
            if nums[i] in dct and dct[nums[i]] + k >= i:
                return True
            dct[nums[i]] = i
        return False
220. 存在重复元素 III

题目: 在整数数组 nums 中,是否存在两个下标 i 和 j,使得 nums [i] 和 nums [j] 的差的绝对值小于等于 t ,且满足 i 和 j 的差的绝对值也小于等于 ķ 。

如果存在则返回 true,不存在返回 false。

示例 1:
输入: nums = [1,2,3,1], k = 3, t = 0
输出: true

示例 2:
输入: nums = [1,0,1,1], k = 1, t = 2
输出: true

示例 3:
输入: nums = [1,5,9,1,5,9], k = 2, t = 3
输出: false

最优解法:利用桶的原理O(n),Python3

  1. 定义桶的大小是t+1, nums[i]//(t+1)决定放入几号桶,这样在一个桶里面的任意两个的绝对值差值都<=t
    例如t=3, nums=[0 ,5, 1, 9, 3,4],那么0号桶就有[0,1,3],1号桶就有[4,5],2号桶就有[9]

  2. 先不考虑索引差值最大为K的限制,那么遍历nums每一个元素,并把他们放入相应的桶中,有两种情况会返回True

    1. 要放入的桶中已经有其他元素了,这时将nums[i]放进去满足差值<=t
    2. 可能存在前面一个桶的元素并且与nums[i]的差值<=t 或者 存在后面一个桶的元素并且与nums[i]的差值<=t
    3. 根据返回True的第一个条件,可以知道前后桶的元素最多也只能有一个。
  3. 接着考虑限制桶中的索引差最大为K,当i>=k的时候:

    • 我们就要去删除存放着nums[i-k]的那个桶(编号为nums[i-k]//(t+1))
    • 这样就能保证遍历到第i+1个元素时,全部桶中元素的索引最小值是i-k+1,就满足题目对索引的限制了
  • Python实现:
class Solution:
    def containsNearbyAlmostDuplicate(self, nums: List[int], k: int, t: int) -> bool:
        if t < 0 or k < 0:
            return False
        buckets = {}
        bucket_size = t + 1                     # 桶的大小设成t+1更加方便
        for i in range(len(nums)):
            bucket_num = nums[i] // bucket_size # 放入哪个桶,对桶进行编号
            
            if bucket_num in buckets:       # 桶中已经有元素了,即该桶中存在满足题目条件的两个索引
                return True
            
            buckets[bucket_num] = nums[i]   # 把nums[i]放入桶中
            
            if (bucket_num - 1) in buckets and abs(buckets[bucket_num - 1] - nums[i]) <= t: # 检查前一个桶
                return True
            
            if (bucket_num + 1) in buckets and abs(buckets[bucket_num + 1] - nums[i]) <= t: # 检查后一个桶
                return True
            
            # 如果不构成返回条件,那么当i >= k 的时候就要删除旧桶了,以维持桶中的元素索引跟下一个i+1索引只差不超过k
            if i >= k:
                buckets.pop(nums[i-k]//bucket_size)
                
        return False
重复N次的数字

题目: 在大小为 2N 的数组 A 中有 N+1 个不同的元素,其中有一个元素重复了 N 次。返回重复了 N 次的那个元素。

示例 1:
输入:[1,2,3,3]
输出:3

示例 2:
输入:[2,1,2,5,3,2]
输出:2

示例 3:
输入:[5,1,5,2,5,3,5,4]
输出:5

提示:
4 <= A.length <= 10000
0 <= A[i] < 10000
A.length 为偶数

解题思路:

  1. 由于A中含有N+1个不同的元素,而仅存在一个重复N次的元素,那么这个元素必定与其左右相邻元素都相等,否则该元素便位于最后一位
  • C++实现:
class Solution {
public:
 int repeatedNTimes(vector<int>& A) {
     int len = A.size();
     for (int i = 0; i < len - 2; i++) {
         if (A[i] == A[i+1] || A[i] == A[i+2]) {
             return A[i];
         }
     }

     // 上面循环没找到,那必然是最后一个数,如[1,2,3,1]
     return A[len - 1];
 }
};

解题思路2:直接利用哈希表

  • Python实现:
class Solution:
    def repeatedNTimes(self, A: List[int]) -> int:
        data = dict()
        for i in A:
            data[i] = data.get(i,0) + 1
        for (key,value) in data.items():
            if value == len(A) //2:
                return key
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值