【专题刷题】双指针(三):两数之和,三数之和,四数之和

📝前言说明:

  • 本专栏主要记录本人的基础算法学习以及LeetCode刷题记录,按专题划分
  • 每题主要记录:(1)本人解法 + 本人屎山代码;(2)优质解法 + 优质代码;(3)精益求精,更好的解法和独特的思想(如果有的话)
  • 文章中的理解仅为个人理解。如有错误,感谢纠错

🎬个人简介:努力学习ing

📋本专栏:C++刷题专栏

📋其他专栏:C语言入门基础python入门基础C++学习笔记Linux

🎀CSDN主页 愚润泽

视频


167. 两数之和 II

个人解

思路:

暴力求解的时间复杂度:O($n^2$)每次移动只能获取一个信息 ,移动 n 2 n^2 n2 次,才能得到所有两数相加的结果。

那使用双指针呢?

使用双指针,利用数组的非递减性(也就是非严格单调递增性)

我们让一个指针指向左边最小的元素,一个指针指向右边最大的元素

要寻找numbers[left] + numbers[right] == target

numbers[left] + numbers[right] > target的时候为例,让right--,移动一次得到n个信息 ,因为当最小数和numbers[right]相加都大于target了,那其他numbers[left]之后更大的数与numbers[right]相加就没有意义了,一下可以排除n个数。left++也同理

用时:3:00

屎山代码:

cpp 复制代码
class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        int left = 1, right = numbers.size();
        while(left < right)
        {
            int sum = numbers[left - 1] + numbers[right - 1];
            if(sum < target)
                left++;
            else if(sum > target)
                right--;
            else
                return {left, right};
        }
        return {-1,-1};
    }
};

时间复杂度:O(n)
空间复杂度:O(1)


优质解

简单题简单做,双指针已够用


15. 三数之和

个人解

思路:用base遍历整个数组,作为基准,将问题转换成nums[left] + nums[right] = 0 - nums[base]的问题。然后基于这个标准(nums[left] + nums[right] = 0 - nums[base]),再利用数组的单调性,再次用双指针。

用时:20:00(为什么这么长,因为题目要求不能重复,被去重坑惨了)

屎山代码:

cpp 复制代码
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        ranges::sort(nums);
        int n = nums.size(), base = 0;
        vector<vector<int>> ans;
        for(; base < n - 2; base++)
        {
            int left = base + 1, right = n - 1;
            while(left < right)
            {
                if(nums[base] + nums[left] + nums[right] < 0)
                    left++;
                else if(nums[base] + nums[left] + nums[right] > 0)
                    right--;
                else
                {
                    ans.push_back({nums[base], nums[left], nums[right]});
                    while(left < right && nums[left + 1] == nums[left])
                        left++;
                    while(left < right && nums[right - 1] == nums[right])
                        right--;
                    left++;
                    right--;
                }
            }
            while(base < n - 3 && nums[base + 1] == nums[base])
                base++;
        }
        return ans;
    }
};

时间复杂度:O( n 2 n^2 n2)
空间复杂度:O(1)


优质解

思路:双指针已经够用

但是我们来欣赏一下别人处理重复元素的思路,以及其他优化,和优雅的代码

代码(来自Leetcode上灵茶山艾府):

cpp 复制代码
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        ranges::sort(nums);
        vector<vector<int>> ans;
        int n = nums.size();
        for (int i = 0; i < n - 2; i++) {
            int x = nums[i];
            // 跳过重复数字,base在使用前确保是唯一的,数组中无重复
            if (i && x == nums[i - 1]) continue; 
            // 优化一(加上两个最小数)
            if (x + nums[i + 1] + nums[i + 2] > 0) break; 
            // 优化二(加上两个最大数)
            if (x + nums[n - 2] + nums[n - 1] < 0) continue; 
            int j = i + 1, k = n - 1;
            while (j < k) {
                int s = x + nums[j] + nums[k];
                if (s > 0) {
                    k--;
                } else if (s < 0) {
                    j++;
                } else { // 三数之和为 0
                    ans.push_back({x, nums[j], nums[k]});
                    // 跳过重复数字(用 for 可以多跳一步,直接跳到不相等的下一个元素)
                    for (j++; j < k && nums[j] == nums[j - 1]; j++); 
                    for (k--; k > j && nums[k] == nums[k + 1]; k--);
                }
            }
        }
        return ans;
    }
};

18. 四数之和

个人解

思路:借助三数之和的解决方法,定好一个base以后又转换成三数之和的问题。

不过这时候优化的地方有两个,因为其实可以看做是有两个base

用时:19:00

cpp 复制代码
class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        ranges::sort(nums);
        vector<vector<int>> ans;
        int n = nums.size();
        for(int base = 0; base < n - 3; base++)
        {   // 错误示范:应该要先用完再去除,因为万一其他数用的和base一样呢?
            // if(base < n - 4 && nums[base + 1] == nums[base])
            //     continue; // 去除重复元素
            if(base && nums[base] == nums[base - 1])
                continue;
            long long x = nums[base]; // 这题老六 数字会溢出
            if(x + nums[base + 1] + nums[base + 2] + nums[base + 3] > target)
                break;
            if(x + nums[n - 3] + nums[n - 2] + nums[n - 1] < target) 
                continue;
            for(int i = base + 1; i < n - 2; i++)
            {
                if(i > base + 1 && nums[i] == nums[i - 1])
                    continue;
                long long y = nums[i];
                if(x + y + nums[i + 1] + nums[i + 2] > target)
                    break;
                if(x + y + nums[n - 2] + nums[n - 1] < target) 
                    continue;
                int j = i + 1, k = n - 1;
                while(j < k)
                {
                    if(x + y + nums[j] + nums[k] < target)
                        j++;
                    else if(x + y + nums[j] + nums[k] > target)
                        k--;
                    else
                    {
                        ans.push_back({(int)x, (int)y, nums[j], nums[k]});
                        for(j++; j < k && nums[j] == nums[j - 1]; j++);
                        for(k--; j < k && nums[k] == nums[k + 1]; k--);
                    }
                }
            }
        }
        return ans;
    }
};

时间复杂度:O( n 3 n^3 n3)
空间复杂度:O(1)

注意跳过重复元素:必须是用完以后base再跳过重复元素 ,因为有可能后面的数可能取和base一样的值,但是被base跳过了就取不到了。

优质解

双指针已足以,暂时不探索其他解


🌈我的分享也就到此结束啦🌈

要是我的分享也能对你的学习起到帮助,那简直是太酷啦!

若有不足,还请大家多多指正,我们一起学习交流!

📢公主,王子:点赞👍→收藏⭐→关注🔍

感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!

相关推荐
孙同学_27 分钟前
【递归,搜索与回溯算法篇】专题(一) - 递归
算法·leetcode
Dovis(誓平步青云)1 小时前
解构C++高级命名空间:构建空间作用域·控制兼容
开发语言·c++·经验分享·笔记·学习方法
Tummer83631 小时前
C语言与C++的区别
c语言·c++·算法
DoorToZen1 小时前
理解 `.sln` 和 `.csproj`:从项目结构到构建发布的一次梳理
经验分享·笔记·其他·前端框架·c#·.net
Arenaschi1 小时前
运用fmpeg写一个背英文单词的demo带翻译
java·笔记·tcp/ip·其他·eclipse·maven
2301_807611492 小时前
47. 全排列 II
c++·算法·leetcode·回溯
✿ ༺ ོIT技术༻2 小时前
笔试强训:Day4
c++·算法
老歌老听老掉牙3 小时前
Open CASCADE学习|实现裁剪操作
c++·学习·opencascade·裁剪
姜行运3 小时前
数据结构【二叉搜索树(BST)】
android·数据结构·c++·c#
RLG_星辰6 小时前
第六章-哥斯拉4.0流量分析与CVE-2017-12615的复现
笔记·安全·网络安全·tomcat·应急响应·玄机