【力扣136】只出现一次的数字

本文介绍了两种高效的算法,一是通过位运算异或找到数组中仅出现一次的数字,二是借助HashSet的特性快速定位单数元素。两种方法都具有线性时间复杂度且不使用额外空间。实例详细解释了如何在给定整数数组中找出那个只出现一次的元素。

题目描述:给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例 1:

输入: [2,2,1]
输出: 1

示例 2:

输入: [4,1,2,1,2]
输出: 4

题目链接
解题思路一:
此题我们可以利用位运算把这个数组里的所有元素异或起来,最终的结果即为我们想要的数字

class Solution {
    public int singleNumber(int[] nums) {
        int single = 0;
        for (int num : nums) {
            single ^= num;
        }
        return single;
    }
}

解题思路二:
同样我们也可以利用set这个集合(利用set不能放重复元素的特性来做),当set这个集合里没有特定的数据时,将此数据放进去,而里面有特定数据时,将set集合里的数据删除同时不放进去,最后再打印出来即可

class Solution {
    public int singleNumber(int[] nums) {
       HashSet<Integer> set = new HashSet<>();
        
        for(int i = 0;i < nums.length;i++) {
            if(set.contains(nums[i])) {
                set.remove(nums[i]);
            }else{
                set.add(nums[i]);
            }
        }

        for(int i = 0;i < nums.length;i++) {
            if(set.contains(nums[i])) {
                return nums[i];
            }
        }
        return -1;
    }
}
<think>好的,我现在需要解决用户的两个问:首先解释MySQL子查询排名逻辑的执行过程,然后提供使用MySQL解决力扣180(连续出现的数字)的解决方案。让我先理清用户的需求和背景。 用户之前已经询问过关于SQL代码执行过程的问,特别是涉及子查询的排名逻辑。现在他们希望更深入地理解MySQL中子查询排名的执行机制,可能是在准备面试或刷时需要掌握这些概念。此外,用户提到了力扣180,这需要找出连续出现至少三次的数字,属于常见的SQL问,通常考察窗口函数或自连接的使用。 首先,针对子查询排名的执行过程。用户之前提供的代码示例使用了子查询来计算排名,我需要详细解释其执行步骤,包括主查询和子查询的交互、逐行处理的方式以及性能特点。根据之前的引用内容,用户可能已经了解一些窗口函数的方法(如引用2中的dense_rank),但这里需要对比子查询方法和窗口函数的区别,尤其是执行过程和效率上的差异。 接下来是力扣180的解决方案。这道的关键在于识别连续出现的记录。常见的方法包括自连接或使用变量来跟踪连续出现的次数。但考虑到用户之前的问中提到了子查询和窗口函数,可能需要提供多种解法,并比较它们的优缺点。例如,使用自连接三次的方法虽然直观,但可能在性能上有问;而使用窗口函数(如lead/lag)会更高效,但需要MySQL 8.0+的支持。此外,用户可能还需要考虑如何处理重复数字但非连续的情况,比如数字中间有其他数字隔开的情况。 需要注意的是,用户提供的引用中有关于窗口函数的使用(引用2和3),以及连接操作的注意事项(引用5),这些都可以在解答中引用。例如,在解决连续数字时,如果使用自连接,需要正确选择JOIN类型,避免LEFT JOIN导致的结果错误(引用5)。同时,如果使用窗口函数,可以引用之前提到的排名函数(如rank() over)来处理。 在回答时,需要确保结构清晰,分步骤解释每个解决方案的执行过程,并比较不同方法的优劣。同时,用户可能希望看到具体的SQL代码示例,以及对其执行过程的详细解释,类似于之前提供的快速排序代码示例。此外,用户可能对性能优化感兴趣,所以需要讨论不同方法的时间复杂度和适用场景。 总结来说,我需要: 1. 详细解释子查询排名的执行过程,包括主查询逐行处理、子查询如何为每一行计算排名,以及相关的性能问。 2. 提供力扣180的多种解决方案,包括自连接、窗口函数和变量法,并分析各自的优缺点。 3. 引用用户之前的问和提供的引用内容,确保回答的一致性和相关性。 4. 确保回答结构清晰,代码正确,并附上执行过程的解释,帮助用户逐步理解。 现在,我需要检查是否有遗漏的部分,例如子查询排名中的DISTINCT使用是否必要,或者在连续数字中如何处理多组连续的情况。同时,需要验证提供的SQL代码是否正确,并考虑不同MySQL版本的支持情况,如窗口函数在MySQL 8.0+才被支持,而变量法可能在旧版本中更适用。 最后,生成相关问,帮助用户进一步巩固知识点,例如优化排名查询的方法,或者处理更复杂的连续出现条件的情况。</think>### **一、MySQL子查询排名逻辑执行过程详解** #### **1. 核心代码回顾** ```sql SELECT s1.score, (SELECT COUNT(DISTINCT s2.score) FROM Scores s2 WHERE s2.score >= s1.score) AS 'rank' FROM Scores s1 ORDER BY s1.score DESC; ``` #### **2. 执行过程分步解析** 1. **主查询逐行扫描** - 从`Scores s1`表中逐行读取每条记录的`score`值,每读取一行,触发一次子查询。 - **示例数据流**:若数据为`[100, 100, 90, 80]`,主查询依次处理`100 → 100 → 90 → 80`。 2. **子查询动态计算排名** - 每次主查询读取一行时,子查询执行以下逻辑: ```sql SELECT COUNT(DISTINCT s2.score) FROM Scores s2 WHERE s2.score >= s1.score -- 关联主查询的当前行 ``` - **关键步骤**: - 筛选所有`>=`当前分数的记录(如处理`100`时,筛选出`[100, 100, 90, 80]`中`>=100`的值)。 - 去重后统计唯一分数数量(如`100`去重后为`1`,`90`去重后统计`>=90`的分数为`100, 90`,结果为`2`)。 3. **结果组装与排序** - 主查询将每个`score`与子查询返回的`rank`组合,最终按`score DESC`排序输出。 #### **3. 性能与特性** - **时间复杂度**:$O(n^2)$,主查询$n$行 × 子查询全表扫描$n$次。 - **排名类型**:实现密集排名(DENSE_RANK),同分同排名且无间隔。 - **适用场景**:小数据集,兼容所有SQL版本(无需窗口函数)[^1]。 --- ### **二、力扣180(连续出现的数字)解决方案** #### **目描述** - 表`Logs`结构:`id INT, num INT` - 要求:找出所有**至少连续出现三次**的数字。 - 示例输入: ``` +----+-----+ | id | num | +----+-----+ | 1 | 1 | | 2 | 1 | | 3 | 1 | | 4 | 2 | | 5 | 1 | | 6 | 2 | | 7 | 2 | +----+-----+ ``` - 期望输出:`[1]`(仅数字1连续出现三次) --- #### **方案1:自连接法(兼容所有版本)** ##### **核心逻辑** 通过三次自连接,筛选连续三条记录中`num`相同的值。 ```sql SELECT DISTINCT a.num AS ConsecutiveNums FROM Logs a JOIN Logs b ON a.id = b.id - 1 AND a.num = b.num JOIN Logs c ON b.id = c.id - 1 AND b.num = c.num; ``` ##### **执行过程** 1. **连接条件**: - `a.id = b.id -1`确保`a`是`b`的前一条记录。 - `a.num = b.num`和`b.num = c.num`保证连续三条记录的`num`相同。 2. **去重**:使用`DISTINCT`避免重复结果。 3. **性能分析**: - **时间复杂度**:$O(n^3)$,三重连接导致性能低下。 - **适用场景**:数据量较小且需兼容老版本MySQL[^5]。 --- #### **方案2:窗口函数法(MySQL 8.0+)** ##### **核心逻辑** 使用`LAG`函数向前取前两条记录的`num`,判断是否连续相同。 ```sql SELECT DISTINCT num AS ConsecutiveNums FROM ( SELECT num, LAG(num, 1) OVER (ORDER BY id) AS prev1, LAG(num, 2) OVER (ORDER BY id) AS prev2 FROM Logs ) AS tmp WHERE num = prev1 AND num = prev2; ``` ##### **执行过程** 1. **窗口函数计算**: - `LAG(num, 1)`获取前一行的`num`。 - `LAG(num, 2)`获取前两行的`num`。 2. **过滤条件**:若当前`num`与前两条记录的`num`均相同,则为目标结果。 3. **性能分析**: - **时间复杂度**:$O(n)$,单表扫描+窗口计算,效率显著高于自连接法[^2]。 --- #### **方案3:变量计数法(兼容老版本)** ##### **核心逻辑** 通过变量跟踪连续出现次数,动态统计连续三次的情况。 ```sql SELECT DISTINCT num AS ConsecutiveNums FROM ( SELECT num, @count := IF(@prev = num, @count + 1, 1) AS cnt, @prev := num FROM Logs, (SELECT @prev := NULL, @count := 0) AS init ORDER BY id ) AS tmp WHERE cnt >= 3; ``` ##### **执行过程** 1. **变量初始化**:`@prev`存储前一个`num`,`@count`统计连续次数。 2. **动态更新**: - 若当前`num`与前一个相同,`@count`自增1。 - 否则重置`@count`为1。 3. **过滤输出**:筛选`cnt >=3`的记录并去重。 4. **性能分析**: - **时间复杂度**:$O(n)$,单次扫描,效率最优。 --- ### **三、方案对比与选择** | 方法 | 优点 | 缺点 | 适用场景 | |---------------|--------------------------|--------------------------|-----------------------| | **自连接法** | 兼容所有SQL版本 | $O(n^3)$,性能差 | 极小数据集 | | **窗口函数法**| $O(n)$,代码简洁 | 需MySQL 8.0+ | 大数据集,现代环境 | | **变量法** | $O(n)$,兼容老版本 | 需处理变量初始化逻辑 | 老版本MySQL优化场景 | --- ### **四、扩展验证(处理非严格连续)** 若目要求**至少三次出现(不要求连续)**,需改用分组统计: ```sql SELECT num FROM Logs GROUP BY num HAVING COUNT(*) >= 3; -- 仅统计出现次数,不限制连续性 ``` --- ### **五、相关问** 1. 如何优化自连接法的性能? 2. 窗口函数`LAG`与`LEAD`的区别是什么? 3. 变量法中若`id`不连续,如何调整逻辑? 4. 如何查找连续出现N次的数字(N为任意值)?
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

春风~十一载

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值