[leetcode]Contains Duplicate III

本文针对LeetCode上的一道难题,提供了两种解决方案:暴力法和利用BinarySearchTree削减无意义搜索的方法。详细介绍了如何使用C++中的map数据结构实现第二种方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

昨天在leetcode上做了这道题,利用了C++中map存储结构的特征。

题意

    Given an array of integers, find out whether there are two distinct indices i and j in the array such that the difference between nums[i] and nums[j] is at most t and the difference between i and j is at most k.

给定一个数组nums,判断:是不是存在两个不同的数(下标分别为i、j),它们满足如下两个条件

  1. | i - j | <= k
  2. | nums[i] - nums[j] | <= t

思路一:两层遍历(暴力法)

这个想法比较简单,我觉得leetcode的这个题也不可能会采用这样的方法。果然,提交下面的代码就超时了。

class Solution {
public:
    bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
        bool res = false;
        int ns = nums.size();

        for(int i = 0; i < ns - 1; i++)
        {
            //int max = 0;
            for(int j = i + 1; j < ns && j <= i + k; j++)
            {
                long result = nums[i] - nums[j];
                if(result > INT_MAX || result <= INT_MIN) return false;

                if(abs(nums[i] - nums[j]) <= t)
                {
                    return true;
                }
            }   

        }
        return res;
    }
};

思路二:利用Binary Search Tree,削减无意义搜索

这个思路利用了C++中的map数据结构的特性,搜索nums数据中在(nums[i] - t, nums[i] + t)范围内的数,并判断其下标是否满足条件1。下面结合代码看一下。

class Solution {
private:
    bool overflow(int one, int two)// 判断两个减数是否越界
    {
        long res = one - two; 
        if(res > INT_MAX || res <= INT_MIN) return true;
        else return false;
    }
public:
    bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
        if(t < 0) return false;
        if(k < 1) return false;

        bool res = false;
        int ns = nums.size();
        map<int, int> hmap; // map<nums[i], i>
        for(int i = 0; i < ns; i++)
        {
            //int max = 0;
            map<int, int>::iterator it = hmap.find(nums[i]);

            if(it != hmap.end()) // 如果i之前有与nums[i]相同的值
            {
                if(abs(it->second - i) <= k) return true; // 下标之差不用判断是否越界。
                it->second = i; // 如果不满足条件1,则将这个结点中的下标覆盖。这个比较好理解,it存在,说明它与之前值都未能满足条件。而i之后的nums肯定离i更近。

            }
            else
            {
                hmap[nums[i]] = i; // 若不存在,则插入
            }

            // 下面利用map迭代器的特征,对nums[i]两边(大小关系)相邻的值进行比较。这些值在(nums[i] - t, nums[i] + t)内。
            map<int, int>::iterator temp_it = hmap.find(nums[i]);

            if(temp_it != hmap.begin()) // it在begin位置,就无需向前了。
            {
                temp_it--;

                while(temp_it != hmap.begin())
                {
                    if(overflow(temp_it->first, nums[i])) return false;
                    if(abs(temp_it->first - nums[i]) > t) break; // 超出条件2的范围,跳出循环

                    if(abs(temp_it->second - i) <= k) return true;

                    temp_it--;
                }

                这个是为了处理begin元素
                if(temp_it == hmap.begin())
                {
                    if(overflow(temp_it->first, nums[i])) return false;
                    if(abs(temp_it->first - nums[i]) <= t)
                    {
                        if(abs(temp_it->second - i) <= k) return true;
                    }
                }
            }


            // 向nums[i] + t方向查找。
            temp_it = hmap.find(nums[i]);
            temp_it++;
            while(temp_it != hmap.end())
            {
                if(overflow(temp_it->first, nums[i])) return false;
                if(abs(temp_it->first - nums[i]) > t) break;

                if(abs(temp_it->second - i) <= k) return true;

                temp_it++;
            }
        }
        return res;
    }
};

总结

通过这个题可以总结map的以下几点特性:

  1. map的存储结构,可以看成是一个搜索二叉树。
  2. map的迭代器的自加自减是在对二叉树进行中序遍历的过程,其实现方式应该是双向中序链表。
  3. map的键值的查找的平均时间复杂度是log级别。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值