219. Contains Duplicate II [easy] (Python)

博客介绍了LeetCode的第219题,题目要求在给定数组中找到差值不超过k的重复元素。文章提供了两种Python解题思路,包括使用字典记录元素下标和维护一个包含最近k个元素的集合。

题目链接

https://leetcode.com/problems/contains-duplicate-ii/

题目原文

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

题目翻译

给定一个数组,和一个整数k,判断该数组中是否存在不同下标的 i 和 j 两个元素,使得 nums[i] = nums[j],且 i 和 j 的差不超过k。

思路方法

暴力两重循环不可取,无法AC。。。

思路一

遍历所有元素,将元素值当做键、元素下标当做值,存放在一个字典中。遍历的时候,如果发现重复元素,则比较其下标的差值是否小于k,如果小于则可直接返回True,否则更新字典中该键的值为新的下标。

代码

class Solution(object):
    def containsNearbyDuplicate(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: bool
        """
        num_map = {}
        for i in xrange(len(nums)):
            if nums[i] in num_map and i - num_map[nums[i]] <= k:
                return True
            else:
                num_map[nums[i]] = i
        return False

思路二

在遍历列表的时候维护一个集合,集合中保存当前元素前面的k个元素,每次访问一个元素时判断是否在该集合中出现过。

代码

class Solution(object):
    def containsNearbyDuplicate(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: bool
        """
        window = set([])
        for i in xrange(len(nums)):
            if i > k:
                window.discard(nums[i-k-1])
            if nums[i] in window:
                return True
            else:
                window.add(nums[i])
        return False

PS: 新手刷LeetCode,新手写博客,写错了或者写的不清楚还请帮忙指出,谢谢!
转载请注明:http://blog.youkuaiyun.com/coder_orz/article/details/51674266

<think> 我们之前讨论了MySQL中REPLACE操作的效率,现在用户想了解INSERT ... ON DUPLICATE KEY UPDATE(以下简称IODKU)的效率和使用情况,特别是与REPLACE操作(REPLACE INTO)的对比。根据引用,我们可以从以下几个方面分析: 1. **效率对比**:引用[3]提到,使用UPDATE更新数据速度为2000/s,而使用IODKU更新速度达到40000/s,效率提升显著。而REPLACE INTO在冲突时是先删除再插入,IODKU则是直接更新,避免了删除操作的开销,因此在更新操作时IODKU效率更高。 2. **工作原理**:IODKU在遇到主键或唯一键冲突时,执行UPDATE操作(只更新指定字段),而不是删除整行再插入。这减少了索引变动、触发器触发(如删除相关的触发器)以及自增ID的浪费。 3. **使用场景**:适合需要根据唯一键判断记录是否存在,存在则更新部分字段,不存在则插入的场景。如用户引用[4]中的例子:记录用户对单词的录音,如果已有记录则更新录音路径和时间。 4. **使用方法**:基本语法如下: ```sql INSERT INTO table (col1, col2, ...) VALUES (val1, val2, ...) ON DUPLICATE KEY UPDATE col1 = val1, col2 = val2, ...; ``` 注意:UPDATE后面可以更新为新的值,也可以引用VALUES函数来使用插入时的值,例如: ```sql INSERT INTO test (a, b) VALUES (1, 2) ON DUPLICATE KEY UPDATE b = VALUES(b); ``` 5. **与REPLACE INTO的对比**: - **操作差异**:REPLACE INTO是删除后插入,整行替换;IODKU是直接更新部分列。 - **效率**:IODKU在更新时效率更高(避免删除和重新插入,减少索引维护)。 - **自增ID**:REPLACE INTO会改变自增ID(旧行删除,新行插入,自增ID增加),而IODKU不会(因为只是更新,原ID保留)。 - **触发器**:REPLACE INTO会触发DELETE和INSERT触发器,而IODKU只触发UPDATE触发器(如果存在)和INSERT触发器(当插入时)或UPDATE(当更新时)。 6. **注意事项**: - 必须存在主键或唯一索引才能触发更新。 - 在高并发下,IODKU比REPLACE INTO性能更好,因为减少了锁的持有时间(引用[3]的实践数据)。 - 使用IODKU会绑定MySQL(引用[1]),因为这是MySQL的扩展语法。 7. **优化建议**: - 只更新需要变更的字段,避免不必要的更新。 - 如果不需要更新所有字段,在UPDATE子句中只列出需要更新的字段。 结合用户之前的问题(REPLACE效率),我们可以这样总结: - 在需要更新部分字段且存在冲突的情况下,优先使用IODKU,因为它效率更高(引用[3]的数据)。 - 在需要整行替换时(即冲突时希望用新数据完全覆盖旧数据),可以使用REPLACE INTO,但要注意其效率较低以及自增ID变化的问题。 接下来,我们将详细说明IODKU的使用方法和效率分析。 </think>### MySQL中`INSERT ... ON DUPLICATE KEY UPDATE`效率与使用分析 结合您关注的效率对比(特别是与`REPLACE INTO`的对比)以及引用内容,以下从效率机制、使用方法和场景建议展开: --- ### 一、核心效率机制 #### 1. **与`REPLACE INTO`的效率对比** | **操作** | **底层行为** | **效率优势** | **效率劣势** | |-------------------------------|-----------------------------|---------------------------------------------------|-------------------------------------| | **REPLACE INTO** | 冲突时:先删除旧行 → 插入新行 | 逻辑简单,适合整行替换 | 1. 自增ID不连续<br>2. 触发`DELETE`触发器<br>3. 索引重建成本高 | | **ON DUPLICATE KEY UPDATE** | 冲突时:直接更新指定字段 | 1. **避免删除操作**<br>2. **仅更新差异字段**<br>3. **保留原自增ID** | 需显式指定更新字段 | **实测数据**(引用[3]): - `UPDATE`:约 2000次/秒 - `ON DUPLICATE KEY UPDATE`:约 **40000次/秒**(效率提升20倍)[^3] > 原因:避免行删除和重建,减少I/O和索引维护。 #### 2. **高效原理** - **最小化写操作**:仅修改冲突字段(如引用[4]中只更新`path`和`time`)[^4] - **原子性保证**:单语句完成"存在则更新,不存在则插入",减少事务开销[^2] - **锁优化**:InnoDB引擎下行级锁,并发性能更高(对比`REPLACE INTO`的表级锁风险) --- ### 二、使用方法与示例 #### 1. **基础语法** ```sql INSERT INTO 表名 (列1, 列2, ...) VALUES (值1, 值2, ...) ON DUPLICATE KEY UPDATE 列1 = 新值1, 列2 = 新值2; ``` #### 2. **实战案例** **场景**:记录用户单词录音,存在相同记录时更新路径和时间(引用[4])[^4] ```sql INSERT INTO kid_big_cat_course_word_recording (user_id, word_id, path, time) VALUES (#{userId}, #{pk}, #{path}, NOW()) ON DUPLICATE KEY UPDATE path = VALUES(path), -- 使用VALUES()引用插入值 time = NOW(); ``` > **关键技巧**: > - 使用`VALUES(列名)`获取插入值,避免重复传参 > - 只更新必要字段(`path`和`time`) #### 3. **自动识别冲突** - **触发条件**:主键(Primary Key)或唯一索引(Unique Index)冲突 - **错误写法**: ```sql ON DUPLICATE KEY UPDATE path = 'new_path'; -- 直接赋固定值(错误!) ``` - **正确写法**: ```sql ON DUPLICATE KEY UPDATE path = VALUES(path); -- 动态引用插入值[^4] ``` --- ### 三、适用场景与限制 #### ✅ **推荐场景** 1. **高并发写入**(如计数器、实时日志) ```sql INSERT INTO page_views (page_id, views) VALUES (123, 1) ON DUPLICATE KEY UPDATE views = views + 1; -- 原子性递增 ``` 2. **数据同步**(避免`SELECT`检查存在性)[^2] 3. **部分字段更新**(如用户配置表,仅更新最后修改时间)[^4] #### ⚠️ **使用限制** 1. **数据库绑定**:MySQL特有语法,迁移到其他数据库需重写(引用[1])[^1] 2. **更新字段**:必须显式列出需更新的列(`REPLACE INTO`默认更新所有列) 3. **触发器行为**: - 冲突时触发`BEFORE UPDATE`和`AFTER UPDATE` - **不触发**`DELETE`相关触发器(与`REPLACE INTO`关键区别) --- ### 四、性能优化建议 1. **精简更新字段** ```sql -- 只更新必要字段 ON DUPLICATE KEY UPDATE status = VALUES(status), update_time = NOW(); -- 而非更新所有列 ``` 2. **避免全表更新** 结合`WHERE`条件限制范围(但需注意:WHERE在IODKU中无效,需前置过滤数据) 3. **索引优化** - 确保冲突检测列(主键/唯一索引)覆盖高频查询 - 避免对更新列建立过多索引(减少写放大) 4. **批量操作加速** ```sql INSERT INTO table (id, data) VALUES (1, 'a'), (2, 'b'), (3, 'c') ON DUPLICATE KEY UPDATE data = VALUES(data); ``` --- ### 五、总结:何时选择`ON DUPLICATE KEY UPDATE` | **需求** | 推荐方案 | |-------------------------|----------------------------| | 冲突时需**更新部分字段** | ✅ `ON DUPLICATE KEY UPDATE` | | 冲突时需**完全替换整行** | ⚠️ `REPLACE INTO`(注意副作用) | | 需要**保留原自增ID** | ✅ `ON DUPLICATE KEY UPDATE` | | 高并发增量更新(如计数器) | ✅ `ON DUPLICATE KEY UPDATE` | > **结论**:在更新为主的场景中,`ON DUPLICATE KEY UPDATE`因避免删除操作和精准字段更新,效率显著高于`REPLACE INTO`(引用[3]实测数据验证)[^3]。唯需注意其MySQL依赖性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值