C++ 优先算法 —— 四数之和(双指针)

目录

题目:四数之和

[1. 题目解析](#1. 题目解析)

[2. 算法原理](#2. 算法原理)

[Ⅰ. 暴力枚举](#Ⅰ. 暴力枚举)

[Ⅱ. 双指针算法](#Ⅱ. 双指针算法)

不漏的处理:

去重处理:

[3. 代码实现](#3. 代码实现)

[Ⅰ. 暴力枚举](#Ⅰ. 暴力枚举)

[Ⅱ. 双指针算法](#Ⅱ. 双指针算法)


题目:四数之和

1. 题目解析

题目截图:

这道题与三数之和(三数之和的解答)及两数之和(两数之和的解答)是很相似的,这道题目要求,也类似于三数之和,它这里的顺序上:

  • 每个四元组的前后顺序可以任意
  • 每个四元组中的数据顺序可以任意

这里target可以不同(target可以随意)。

2. 算法原理

这里也是同样有两种解法:

  • 暴力枚举
  • 双指针算法

Ⅰ. 暴力枚举

这里方法也是:排序+暴力枚举(从左往右)+去重

类比前面的三数之和

cpp 复制代码
//伪代码演示
for (int i = 0; i < n; i++) // 固定一个数a

    for (int j = i + 1; j < n; j++)     //依次固定枚举第二个数
    
        for (int k = j + 1; k < n; k++)    //枚举第三个数
        
            for(int z = k + 1; z < n; z++)    //枚举第四个数
            
                查找符合的四元组,去重...
  

这里套了四层for循环,时间复杂度就是O(N⁴)。(会出现超时问题)

Ⅱ. 双指针算法

这里同三数之和也是:排序+双指针+去重

这里就相当于划分成,固定第一个数,剩下的就是利用三数之和思想解决,三数之和中,也是要固定一个数(这里也就是第二个数),接着利用两数之和解决,也就是在剩下的区间内用双指针算法。

总结一下解决方法:

  1. 依次固定一个数a(从左往右固定a,固定枚举完这一个后,再换下一个)。
  2. 在a的后面的区间内,利用"三数之和"的思想,找到三个数,使这三个数的和等于target-a即可。

这里三数之和:

  1. 依次固定一个数b。
  2. 在b后面的区间内,利用双指针,找到两个数,使这两个数的和等于target-a-b即可。

通过上图可以看到需要套两次for循环加一个while,时间复杂度为O(N²)

这里也是需要处理同三数之和的细节问题:

不漏的处理:

也就是确保所有符合条件的情况不漏掉,这里也是找到一种结果之后,不要停(两个指针不停),缩小区间(两指针都向内移动一步),继续寻找符合的情况。

去重处理:

这里需要考虑三个去重情况:

cpp 复制代码
//伪代码演示
for (i = 0; i < n; i++)  //固定数a		
		//利用三数之和
    for (j = i + 1; j < n; j++)  //固定数b
		//双指针
		while (left < right) 
		//处理数据,并去重		

        //这里去重同样注意越界问题的判断:
        left < right
        j < n
        i < n

接下来,实现代码。

3. 代码实现

题目链接:四数之和

Ⅰ. 暴力枚举

cpp 复制代码
//这里时间复杂度:O(N⁴)
class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        // 1.排序
        sort(nums.begin(), nums.end());

        vector<vector<int>> ret; // 用来存储所有的四元组
        // 2.暴力枚举
        int n = nums.size();
        int i, j, k, z;
        for (i = 0; i < n;) // 固定一个数a
        {
            for (j = i + 1; j < n;) // 依次固定枚举第二个数
            {
                for (k = j + 1; k < n;) // 枚举第三个数
                {
                    for (z = k + 1; z < n;)  // 枚举第四个数
                    {
                        long long sum = (long)nums[i] + nums[j] + nums[k] + nums[z];
                        if (sum == target) 
                        {
                            ret.push_back({nums[i], nums[j], nums[k], nums[z]});
                        }
                        // 去重z
                        ++z;
                        while (z < n && nums[z] == nums[z - 1]) 
                        {
                            ++z;
                        }
                    }

                    // 去重k
                    ++k;
                    while (k < n && nums[k] == nums[k - 1]) 
                    {
                        ++k;
                    }
                }
                // 去重j
                ++j;
                while (j < n && nums[j] == nums[j - 1]) 
                {
                    ++j;
                }
            }
            // 去重i
            ++i;
            while (i < n && nums[i] == nums[i - 1]) 
            {
                ++i;
            }
        }
        return ret;
    }
};

提交记录(这里按理说会超时,时间复杂度:O(N⁴),但这里通过了):

Ⅱ. 双指针算法

cpp 复制代码
//这里时间复杂度是O(N²)
class Solution {
public:
	vector<vector<int>> fourSum(vector<int>& nums, int target) {
		// 1.排序
		sort(nums.begin(), nums.end());

		vector<vector<int>> ret;
		int n = nums.size();
		// 2.利用双指针算法
		int i, j;
		for (i = 0; i < n;)  //固定数a
		{
			//利用三数之和
			for (j = i + 1; j < n;)  //固定数b
			{
				//双指针
				int left = j + 1;
				int right = n - 1;
				long long t = (long)target - nums[i] - nums[j];  //注意数据溢出问题,用long long解决
				while (left < right) 
				{
					int sum = nums[left] + nums[right];
					if (sum > t) 
					{
						--right;
					}
					else if (sum < t) 
					{
						++left;
					}
					else 
					{
						// 将获取的四元组尾插ret里
						ret.push_back({ nums[i], nums[j], nums[left++], nums[right--] });
						// 缩小区间查找
						// 不漏,去重

						// 去重left和right,注意区间越界问题
						while (left < right && nums[left] == nums[left - 1]) 
						{
							++left;
						}
						while (left < right && nums[right] == nums[right + 1])
						{
							--right;
						}
					}
				}
				// 注意j的去重
				++j;
				while (j < n && nums[j] == nums[j - 1]) 
				{
					++j;
				}
			}
			// 注意去重i
			++i;
			while (i < n && nums[i] == nums[i - 1]) 
			{
				++i;
			}
		}
		return ret;
	}
};

提交记录:

制作不易,若有不足之处或出问题的地方,请各位大佬多多指教 ,感谢大家的阅读支持!!!

相关推荐
泡海椒3 分钟前
Java 后端最优 PDF 导出方案:jquick-pdf 项目引入与快速测试
java·开发语言·pdf
钓鱼的肝4 分钟前
csp-j-s总结(1)
c++·笔记·算法·青少年编程
流云枫4 分钟前
001-Transformer架构与Self-Attention机制深度解析
算法
Evand J4 分钟前
【MATLAB例程】二维Astar路径规划与AOA-TDOA定位仿真。完整代码,附下载链接。包运行成功,带中文注释
开发语言·matlab·路径规划·代码·定位·融合定位
李永奉7 分钟前
中科蓝讯SDK开发-耳机项目功耗问题排查教程
c语言·开发语言·嵌入式硬件·物联网·智能手机
生信大杂烩25 分钟前
Xenium H&E空间原位可视化——细胞轮廓、基因表达与转录本可视化
python·算法·数据分析
linx29537 分钟前
第七章 · 标准库容器、算法与 ranges
c语言·开发语言·数据结构·c++·算法
钓鱼的肝41 分钟前
csp-j-s总结(4)
c++·经验分享·笔记·算法
峥嵘life1 小时前
2026华为AI码道 CodeArts 使用分享:Windows端 + 服务器CLI 实战总结
android·大数据·开发语言·python
Logic1011 小时前
C语言/数据结构位运算题解:异或XOR找出独特数字的索引位置——成对数字在两侧
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质