leetcode15三数之和(重点讲去重)

本文主要讲解三数之和的要点与细节,主要讲解利用双指针的方法解决,按照步骤一步步思考方便理解

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组

c++与java代码如下,末尾

具体要点:
1.
本题核心要点在于,三元组里面的数的顺序是不重要的,结果不能包含重复的三元组

        这就要求我们要对结果进行去重的操作,也是本题最需要考虑清楚的


2. 这道题我们可以采用双指针(滑动窗口)或者 哈希表的方法来处理,但是相比于哈希表,双指针考虑去重要更简单一点,我们先重点讲解双指针的解法


3. 一直说去重去重,到底是什么呢?

去重的核心操作是:判断上一个或者下一个值是否等于当前值,若等于,就跳过,再去判断下一个


4. 所以我们第一步就要对数组进行排序,目的是让相同的值都挨在一起,方便去重


5. 然后我们for循环遍历数组,获取a的值,即nums[i]

然后我们需要考虑一下a去重的问题:如果 i 和 i-1 位置的值相等,那么就跳过(这里有小细节最后讲)

         if (i > 0 && nums[i] == nums[i - 1]) continue;


6. 接着在a=nums[i]条件下,定义两个指针 left = i + 1 和 right = nums.size() - 1,其值分别代表b和c

        记录 sum=nums[i] + nums[left] + nums[right]

        然后就开始滑动,通过判断sum和0的大小

        若sum>0则right--

        若sum<0则left++

        若sum==0则把i、left、right加入结果


7. 当我们 “sum==0则把i、left、right加入结果”之后,我们需要向中间移动left和right,但是移动后位置会出现和上个位置重复值的情况,此时我们就要对 b 和 c 去重了

//对b去重,此时判断的是下一个位置,因为要确定移动到哪
while (left < right && nums[right] == nums[right - 1]) right--;
//对c去重,此时判断的是下一个位置,因为要确定移动到哪
while (left < right && nums[left] == nums[left + 1]) left++;
//直到没有重复的,我们就正常移动
left++;
right--;

最后返回result即可 


8. 细节问题

        a,b,c去重操作一样吗,好像还不太一样

        a比较的是 nums[i] 与 nums[i - 1]。是和移动的上一个进行比较

        b和c比较的是 nums[right] == nums[right - 1] 与 nums[left] == nums[left + 1]。是和移动的下一个位置进行比较(虽然right是-,left是+,但是他们是往中间移动)

        为什么a的i不能和i+1比较呢?

        因为,i+1的位置放的是left呀(b)!   a不需要和b进行去重呀!abc三者重复是可以的

        理解不了?举个例子:nums={-1,-1,-2}

        a是第一个-1,如果i和i+1比较,下一个也是-1,就跳过咯,a直接指向第二个-1(left和right也取不到第一个-1),就错了


c++代码:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        //定义一个vector保存结果
        vector<vector<int>> result;
        //对数组排序
        sort(nums.begin(), nums.end());

        for (int i = 0; i < nums.size(); i++) {
            if (nums[i] > 0)return result;

            //对a去重,此时判断的是上一个位置,如果判断的是下一位,就大错特错,因为下一位放的是left,left和i相等是不影响结果的
            if (i > 0 && nums[i] == nums[i - 1]) continue;

            //定义两个指针
            int left = i + 1;
            int right = nums.size() - 1;
            //执行滑动操作
            while (left < right) {
                int sum=nums[i] + nums[left] + nums[right];
                if (sum > 0) {
                    right--;    
                }
                else if (sum < 0) {
                    left++;
                }
                else {
                    result.push_back(vector<int>{nums[i], nums[left], nums[right]});
                    //对b去重,此时判断的是下一个位置,因为要确定移动到哪
                    while (left < right && nums[right] == nums[right - 1]) right--;
                    //对c去重,此时判断的是下一个位置,因为要确定移动到哪
                    while (left < right && nums[left] == nums[left + 1]) left++;
                    left++;
                    right--;
                }
                    
            }
        }
        return result;

    }
};

java代码

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        //先排序
        Arrays.sort(nums);
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] > 0) return result;
            //去重a
            if (i > 0 && nums[i] == nums[i - 1]) continue;
            //定义双指针
            int left = i + 1, right = nums.length - 1;
            //双指针滑动
            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                if(sum>0){
                    right--;
                }
                else if (sum < 0) {
                    left++;
                }
                else {
                    //等于0,添加进resul
                    result.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    //添加完成后,移动b和c,准备对下一个位置循环,在此之前,要先去重操作,不然移动了还会有重复的
                    while (left < right && nums[left] == nums[left + 1]) left++;
                    while (left < right && nums[right] == nums[right - 1]) right--;
                    
                    //去重完成,移动b和c
                    right--;
                    left++;
                }
            }
        }
        return result;
    }
}

<think>好的,用户之前已经问过如何成为初级软件测试人员,现在他们进一步询问关于熟悉SQL和Linux基本操作的详细内容。我需要先理解他们的需求。用户可能已经按照之前的学习路径开始学习,现在需要更深入的具体指导。 首先,用户是小白,所以需要从基础起。SQL和Linux在测试中很要,比如数据库查询和服务器日志查看。要确保内容详细但不过于复杂,分步骤列出需要掌握的知识点。 对于SQL部分,应该包括基本查询语句,如SELECT、INSERT、UPDATE、DELETE,还有更高级的连接查询和子查询。需要推荐一些练习方法,比如安装MySQL,使用在线平台或自己创建测试数据。常见问题如表连接和也是测试中常遇到的,需要提到。 然后是Linux部分,测试人员常用命令有哪些?比如文件操作的ls、cd、cp,文本处理的cat、grep,权限管理chmod,进程管理ps、kill,以及压缩解压命令。此外,查看日志和分析是测试中的要任务,需要教如何用tail、grep过滤日志,以及使用vi进行编辑。环境变量和简单的脚本编写也可能用到,可以简单介绍。 还要考虑用户的实际应用场景,比如在测试中如何利用这些技能。例如,通过SQL验证数据是否正确,用Linux命令查看服务器日志定位问题。推荐的学习资源如菜鸟教程、实验楼,以及练习方法,如搭建虚拟机或使用在线环境。 用户可能没有Linux环境,所以需要建议安装虚拟机或使用在线平台。同时,练习案例要具体,比如创建测试表、模拟日志分析,让用户有明确的实践目标。常见问题方面,要解答权限不足、连接数据库失败等情况,帮助用户排除困难。 最后,总结这两项技能的要性,并鼓励用户动手实践。确保内容结构清晰,分点明确,语言通俗易懂,适合小白学习。</think>好的!作为初级软件测试人员,熟悉 **SQL** 和 **Linux 基本操作** 是必备技能,以下是具体需要掌握的内容和详细学习清单。这些技能能帮助你完成数据验证、日志分析、环境部署等日常测试任务。 --- ### **一、熟悉 SQL(以 MySQL 为例)** #### **1. 基础语法** - **数据库操作** ```sql CREATE DATABASE test_db; -- 创建数据库 DROP DATABASE test_db; -- 删除数据库 USE test_db; -- 切换数据库 ``` - **表操作** ```sql CREATE TABLE users ( -- 创建表 id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50), age INT, email VARCHAR(100) ); DROP TABLE users; -- 删除表 ALTER TABLE users ADD COLUMN address VARCHAR(200); -- 修改表结构 ``` - **数据操作(CRUD)** ```sql -- 插入数据 INSERT INTO users (name, age, email) VALUES ('张三', 25, '[email protected]'); -- 查询数据 SELECT * FROM users; -- 查询所有字段 SELECT name, age FROM users WHERE age > 20; -- 条件查询 -- 更新数据 UPDATE users SET age = 26 WHERE name = '张三'; -- 删除数据 DELETE FROM users WHERE id = 1; ``` #### **2. 高级查询** - **多表关联查询** ```sql -- 内连接(INNER JOIN) SELECT orders.order_id, users.name FROM orders INNER JOIN users ON orders.user_id = users.id; -- 左连接(LEFT JOIN) SELECT users.name, orders.order_id FROM users LEFT JOIN orders ON users.id = orders.user_id; ``` - **聚合函数与分组** ```sql SELECT COUNT(*) FROM users; -- 统计行数 SELECT AVG(age) FROM users; -- 平均值 SELECT age, COUNT(*) FROM users GROUP BY age; -- 按年龄分组统计 ``` - **子查询** ```sql SELECT name FROM users WHERE id IN (SELECT user_id FROM orders WHERE amount > 100); ``` #### **3. 实战场景** - **测试数据验证** 例如:检查订单表(orders)中的支付状态是否正确。 ```sql SELECT order_id, status FROM orders WHERE status != 'paid'; ``` - **数据准备与清理** 例如:在测试前插入测试数据,测试后删除脏数据。 ```sql -- 插入测试数据 INSERT INTO users (name) VALUES ('测试用户'); -- 清理测试数据 DELETE FROM users WHERE name LIKE '测试%'; ``` #### **4. 学习建议** - **工具**:安装 MySQL + Navicat/DBeaver(图形化工具)。 - **练习平台**:LeetCode SQL题、牛客网SQL题库。 - **常见问题**: - 表连接时字段类型不匹配导致报错。 - 忘记 `WHERE` 条件误删全表数据(⚠️ 慎用 `DELETE` 和 `UPDATE`)。 --- ### **二、Linux 基本操作** #### **1. 常用命令** - **文件与目录操作** ```bash ls -l # 查看目录内容(详细信息) cd /home/test # 切换目录 pwd # 显示当前路径 mkdir test_dir # 创建目录 rm -rf test_dir # 强制删除目录(慎用!) cp file1 file2 # 复制文件 mv file1 dir/ # 移动文件 ``` - **文件内容查看与编辑** ```bash cat log.txt # 查看文件全部内容 head -n 10 log.txt # 查看文件前10行 tail -f log.txt # 实时跟踪日志(测试常用!) grep "error" log.txt # 搜索包含 "error" 的行 vi log.txt # 用vi编辑器修改文件(需掌握基本操作) ``` - **权限管理** ```bash chmod 755 script.sh # 修改文件权限(用户:读写执行,其他用户:读执行) chown user:group file # 修改文件所有者 ``` - **进程与系统管理** ```bash ps -ef | grep java # 查看Java进程 kill -9 1234 # 强制终止进程(PID为1234) top # 实时监控系统资源(CPU、内存) ``` - **压缩与解压** ```bash tar -czvf logs.tar.gz /var/logs # 压缩目录为tar.gz tar -xzvf logs.tar.gz # 解压tar.gz文件 ``` #### **2. 测试常用场景** - **查看日志定位问题** 例如:查找 Tomcat 日志中的异常信息。 ```bash cd /opt/tomcat/logs tail -f catalina.out | grep "Exception" ``` - **部署测试环境** 例如:启动一个 Java 服务。 ```bash nohup java -jar test-app.jar > app.log 2>&1 & ``` - **批量处理测试文件** 例如:批量命名日志文件。 ```bash for file in *.log; do mv "$file" "test_$file"; done ``` #### **3. 学习建议** - **环境搭建**: - 安装虚拟机(VirtualBox + Ubuntu/CentOS)。 - 使用在线实验环境(如 实验楼、腾讯云开发者实验室)。 - **实战练习**: - 用 `grep` 过滤日志中的错误信息。 - 编写 Shell 脚本批量清理测试日志。 - **常见问题**: - 权限不足时用 `sudo` 提权(如 `sudo vi /etc/hosts`)。 - 命令参数错误导致误删文件(⚠️ 慎用 `rm -rf`)。 --- ### **三、SQL + Linux 综合练习案例** 1. **场景**:测试环境数据库异常,需通过日志和SQL排查问题。 2. **步骤**: - 用 `grep` 在日志中搜索 `SQLException`。 - 登录 MySQL 检查相关表的数据是否完整。 - 执行 SQL 修复脏数据(如 `UPDATE` 或 `ROLLBACK`)。 --- ### **四、学习资源推荐** - **SQL**: - 书籍:《SQL必知必会》 - 网站:[SQLZoo](https://sqlzoo.net/)(免费练习) - **Linux**: - 书籍:《鸟哥的Linux私房菜》 - 视频:B站搜索“Linux入门教程” --- 掌握以上内容后,你将能够: 1. 独立完成数据库查询、数据验证和修复。 2. 通过Linux命令分析日志、部署测试环境。 3. 在测试任务中快速定位后端问题(如接口报错、数据不一致)。 **重点**:多动手实践!尝试在虚拟机或云服务器上搭建MySQL和Linux环境,模拟真实测试场景。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值