首页 > 编程语言 >算法练习:两指针之三数之和为0

算法练习:两指针之三数之和为0

时间:2022-12-07 17:33:44浏览次数:43  
标签:mTempArray int mSrcArray 之三 back 算法 push size 指针


问题描述

给出一个整型数组,找出所有三个元素的组合,其组合之和等于0。要求在结果集里不含有重复的组合。

举例:

输入{-2, 1, -1, 2, 1}

输出{-2, 1, 1 }

 

问题分析

最容易想到的是穷举法,挑选第一个元素,然后在其后挑选第二个元素,再从除已经挑选出的两个元素之外挑第三个元素,判断三者之和是否为0;第二种想到的是用回溯递归,这两种方法的时间复杂度均为O(n^3),可参阅代码部分关于这两种方法的实现。

那有没有复杂度低一些的呢,答案是有的,就是使用两指针的方法,从而使复杂度下降到O(n^2)。

首先,将数组按从小到大的排序,然后从头挑选一个元素,接着使用首尾两个指针来挑选后两个元素。如图所示(可结合后面实现代码理解):

 

算法练习:两指针之三数之和为0_#include

 

代码实现

 

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;


typedef vector<int> IntArray;
typedef vector<IntArray> ResultSet;


ResultSet gResultSet; //结果集


//穷举法
void GetResultSet( const IntArray& mSrcArray )
{
for( int i = 0; i < mSrcArray.size(); )
{
for( int j = i + 1; j < mSrcArray.size(); )
{
for( int k = j + 1; k < mSrcArray.size(); )
{
if ( ( mSrcArray[i] + mSrcArray[j] + mSrcArray[k] ) == 0 )
{
IntArray mTempArray;
mTempArray.push_back( mSrcArray[i] );
mTempArray.push_back( mSrcArray[j] );
mTempArray.push_back( mSrcArray[k] );
gResultSet.push_back( mTempArray );
}

//避免重复
do{ ++k; } while( k < mSrcArray.size() && mSrcArray[k-1] == mSrcArray[k] );
}
//避免重复
do{ ++j; } while( j < mSrcArray.size() && mSrcArray[j-1] == mSrcArray[j] );
}
//避免重复
do{ ++i; } while( i < mSrcArray.size() && mSrcArray[i-1] == mSrcArray[i] );
}
}


//两指针法
void GetResultSet_2Ptr( const IntArray& mSrcArray )
{
for( int k = 0; k < mSrcArray.size(); ++k )
{
//第一个数大于0,因为是从小到大排了序的,所以以下就不可能了。
if ( mSrcArray[k] > 0 ) break;

//去除重复结果
if ( k > 0 && mSrcArray[k] == mSrcArray[k-1] ) continue;

int i = k + 1;
int j = mSrcArray.size()-1;

//两指针向中间靠拢找结果
while( i < j )
{
int sum = mSrcArray[i] + mSrcArray[j] + mSrcArray[k];

//和过小,左边指针移动
if ( sum < 0 )
{
++i;
}
//和过大,右边指针移动
else if ( sum > 0 )
{
--j;
}
//找到一个结果
else
{
IntArray mTempArray;
mTempArray.push_back( mSrcArray[k] );
mTempArray.push_back( mSrcArray[i] );
mTempArray.push_back( mSrcArray[j] );
gResultSet.push_back( mTempArray );

//避免重复
do{ ++i; } while( i < j && mSrcArray[i-1] == mSrcArray[i] );

//避免重复
do{ --j; } while( i < j && mSrcArray[j] == mSrcArray[j+1] );
}
}


}
}


//回溯法(递归)
void GetResultSet_Recursive( const IntArray& mSrcArray, IntArray& mDstArrayTemp, int iStart, int nTarget )
{
if ( nTarget == 0 && mDstArrayTemp.size() == 3 )
{
gResultSet.push_back( mDstArrayTemp );
}
else
{
for( int i = iStart; i < mSrcArray.size(); ++i )
{
//数量已经超过3,不能再加入了
if ( mDstArrayTemp.size() >= 3 ) break;

//避免重复加入
if ( i > iStart && mSrcArray[i] == mSrcArray[i-1] ) continue;

mDstArrayTemp.push_back( mSrcArray[i] );

GetResultSet_Recursive( mSrcArray, mDstArrayTemp, i+1, nTarget + mSrcArray[i] );

//回溯
mDstArrayTemp.pop_back();
}
}
}



//打印结果集
void OutSubSets()
{
for( ResultSet::iterator it = gResultSet.begin();
it != gResultSet.end(); ++it )
{
for( IntArray::iterator itTemp = it->begin();
itTemp != it->end(); ++itTemp )
{
cout << *itTemp << " ";
}
cout << endl;
}
cout << "--------------------------------------------" << endl;
}


int main()
{
IntArray mSrcArray;
int nTemp;
while( true )
{
mSrcArray.clear();
while( cin >> nTemp )
{
if ( nTemp == 0 ) break;
mSrcArray.push_back( nTemp );
}

//排序
sort( mSrcArray.begin(), mSrcArray.end() );


gResultSet.clear();
//GetResultSet( mSrcArray );
//GetResultSet_2Ptr( mSrcArray );

IntArray mDstArrayTemp;
GetResultSet_Recursive( mSrcArray, mDstArrayTemp, 0, 0 );



//打印结果集
OutSubSets();
}


return 0;
}



系列文章说明:
1.本系列文章[算法练习],仅仅是本人学习过程的一个记录以及自我激励,没有什么说教的意思。如果能给读者带来些许知识及感悟,那是我的荣幸。
2.本系列文章是本人学习陈东锋老师《进军硅谷,程序员面试揭秘》一书而写的一些心得体会,文章大多数观点均来自此书,特此说明!
3.文章之中,难免有诸多的错误与不足,欢迎读者批评指正,谢谢.

作者:山丘儿 


标签:mTempArray,int,mSrcArray,之三,back,算法,push,size,指针
From: https://blog.51cto.com/u_15905375/5919843

相关文章

  • 算法练习:两数之和
    题目:给定一个整型数组,是否能找出两个数使其和为指定的某个值?注:整型数组中不存在相同的数。一、解题方法1、暴力解法(时间复杂度O(n^2) )这是最容易想到的一种方法,即使用两......
  • 操作系统:银行家算法(避免死锁)
    算法介绍:程序实现:/*****************************************************程序:银行家算法实现作者:小单时间:2013年11月5日***************************......
  • KMP算法详解-字符串匹配
    1.什么是KMP是由这三位学者发明的:Knuth,Morris和Pratt,所以取了三位学者名字的首字母。所以叫做KMP2.KMP的用处KMP主要用于字符串匹配。KMP的主要思想是当出现字符串不匹......
  • 算法练习:两指针之有序数组去重
    问题描述给出一个有序数组,就地移除重复元素,保持每个元素只出现一次,并返回新数组的长度。 问题分析这个比较简单,直接使用两个指针,一个在前,一个在后,扫描一遍数组即可。时间复......
  • 算法练习:两指针之三色排序
    问题描述输入一个整型数组,每个元素在0~2之间,其中0,1,2分别代表红、白、蓝。现要求对数组进行排序,相同颜色的在一起,而且按红白蓝顺序先后排列。要求时间复杂度为O(n)。 问题分......
  • 注意!!一定要谨慎使用c/c++原生指针
    主要是顶层逻辑中引用了一个指针,而在业务逻辑中将此指针删除了。这种在代码量很少的情况下,很容易被发现,但是代码量多了,逻辑多了的时候,想一下子定位到问题所在,就没那么容易了......
  • 三.双指针
    ​​面试题16.06.最小差​​classSolution:defsmallestDifference(self,a:List[int],b:List[int])->int:a.sort();b.sort()i=j=0......
  • 五. 排序算法
    1.定义:1.1原地排序和非原地排序def.原地排序算法使用恒定的的额外空间来产生输出。原地排序:选择排序,插入排序,希尔排序,快速排序,堆排序。非原地排序:归并排序,计数排序,基数排......
  • 一致性哈希算法详解
    一致性哈希是什么,使用场景,解决了什么问题?转载:https://mp.weixin.qq.com/s/hJHMlbQpANwMjx9BetwkUg 1.如何分配请求大多数网站背后肯定不是只有一台服务器提供服务,因......
  • 数据挖掘算法-KNN算法
    ✅作者简介:热爱科研的算法开发者,Python、Matlab项目可交流、沟通、学习。......