15. 3Sum
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note: The solution set must not contain duplicate triplets.
For example, given array S = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
}
};
解题思路:
-
自己的解题思路
一开始打算用两个指针技术,进行求解。但是遇到
“
下一步怎么走
“
问题。
最后用了一个重复查询的方法,进行搜索。
-
别人的解题思路
别人用的两个指针技术与我的不同,他是先确定一点,然而左右搜。我的则是先确定前后两点,然后再确定一点。
学习收获:
-
对于不重复的,可以采用 pre-check 技术,直接转到下一个不重复的值。
-
知道 reserve() 对运行时间的影响
-
熟悉了 unique(),resize(),distance()[ 在 <iterator> 里面 ], 以及 erase() 操作。
-
对于 vector 的 erase() 只改变 size, 而且分 2 个版本: (1) 删除 1 个值 (2) 删除一个区间。
//操作1
auto
it
=
unique
(
res
.
begin
(),
res
.
end
());
res
.
resize
(
distance
(
res
.
begin
(),
it
));
//操作2
auto
it
=
unique
(
res
.
begin
(),
res
.
end
());
res
.
erase
(
it
,
res
.
end
());
附件:程序
1
、自己的程序:
版本
1
:运用下标,进行搜索
vector
<
vector
<
int
>>
threeSum
(
vector
<
int
>&
nums
)
{
bool
myComp
(
vector
<
int
>
&
a
,
vector
<
int
>
&
b
);
sort
(
nums
.
begin
(),
nums
.
end
());
vector
<
int
>
temp
(
3
);
vector
<
vector
<
int
>>
res
;
auto
size
=
nums
.
size
();
if
(
size
>=
3
)
{
decltype
(
size
)
st
=
0
;
decltype
(
size
)
ed
=
size
-
1
;
while
((
ed
-
st
)
>=
1
&&
nums
[
st
]
<=
0
&&
nums
[
ed
]
>=
0
)
{
while
((
ed
-
st
)
>=
1
&&
nums
[
ed
]
>=
0
)
{
int
wt
=
-(
nums
[
st
]
+
nums
[
ed
]);
auto
mid
=
find
(
nums
.
begin
()
+
st
+
1
,
nums
.
begin
()
+
ed
,
wt
);
if
(
mid
!=
nums
.
begin
()
+
ed
)
{
temp
[
0
]
=
nums
[
st
];
temp
[
1
]
=
*
mid
;
temp
[
2
]
=
nums
[
ed
];
res
.
push_back
(
temp
);
}
--
ed
;
}
while
((
ed
-
st
)
>=
1
&&
nums
[
st
]
==
nums
[
st
+
1
])
{
++
st
;
}
++
st
;
ed
=
size
-
1
;
}
}
auto
it
=
unique
(
res
.
begin
(),
res
.
end
());
res
.
resize
(
distance
(
res
.
begin
(),
it
));
return
res
;
}
改进版
1
:改进后的程序,不再需要
unique()
操作
vector
<
vector
<
int
>>
threeSum
(
vector
<
int
>&
nums
)
{
bool
myComp
(
vector
<
int
>
&
a
,
vector
<
int
>
&
b
);
sort
(
nums
.
begin
(),
nums
.
end
());
vector
<
int
>
temp
(
3
);
vector
<
vector
<
int
>>
res
;
res
.
reserve
(
100
);
auto
size
=
nums
.
size
();
if
(
size
>=
3
)
{
decltype
(
size
)
st
=
0
;
decltype
(
size
)
ed
=
size
-
1
;
while
((
ed
-
st
)
>=
1
&&
nums
[
st
]
<=
0
&&
nums
[
ed
]
>=
0
)
{
while
((
ed
-
st
)
>=
1
&&
nums
[
ed
]
>=
0
)
{
int
wt
=
-(
nums
[
st
]
+
nums
[
ed
]);
auto
mid
=
find
(
nums
.
begin
()
+
st
+
1
,
nums
.
begin
()
+
ed
,
wt
);
if
(
mid
!=
nums
.
begin
()
+
ed
)
{
temp
[
0
]
=
nums
[
st
];
temp
[
1
]
=
*
mid
;
temp
[
2
]
=
nums
[
ed
];
res
.
push_back
(
temp
);
}
while
((
ed
-
st
)
>=
1
&&
nums
[
ed
]
==
nums
[
ed
-
1
])
{
--
ed
;
}
--
ed
;
}
while
((
ed
-
st
)
>=
1
&&
nums
[
st
]
==
nums
[
st
+
1
])
{
++
st
;
}
++
st
;
ed
=
size
-
1
;
}
}
return
res
;
}
版本
2
:运用迭代器,进行搜索
vector
<
vector
<
int
>>
threeSum
(
vector
<
int
>&
nums
)
{
vector
<
vector
<
int
>>
res
;
if
(
nums
.
size
()
<
3
)
{
return
res
;
}
sort
(
nums
.
begin
(),
nums
.
end
());
auto
p
=
nums
.
begin
();
auto
q
=
nums
.
begin
()
+
1
;
for
(;
p
<
nums
.
end
()
-
1
;)
{
while
(
q
!=
nums
.
end
())
{
int
toFind
=
-(*
p
+
*
q
);
auto
pos
=
find
(
q
+
1
,
nums
.
end
(),
toFind
);
if
(
pos
!=
nums
.
end
())
{
res
.
push_back
({
*
p
,
toFind
,
*
q
});
}
if
(
toFind
<
0
)
{
break
;
}
else
{
auto
pre_q
=
q
+
1
;
while
(
pre_q
!=
nums
.
end
()
&&
(*
pre_q
==
*
q
))
{
++
pre_q
;
}
q
=
pre_q
;
}
}
auto
pre_p
=
p
+
1
;
while
(
pre_p
<
(
nums
.
end
()
-
1
)
&&
(*
pre_p
==
*
p
))
{
++
pre_p
;
}
p
=
pre_p
;
q
=
p
+
1
;
}
return
res
;
}
版本
3
:使用
Two-pointer tech
,但是无法通过所有的
cases
vector
<
vector
<
int
>>
threeSum
(
vector
<
int
>&
nums
)
{
vector
<
vector
<
int
>>
res
;
if
(
nums
.
size
()
<
3
)
{
return
res
;
}
sort
(
nums
.
begin
(),
nums
.
end
());
auto
p
=
nums
.
begin
();
auto
q
=
nums
.
end
()
-
1
;
while
(
p
<
q
)
{
int
toFind
=
-(*
p
+
*
q
);
auto
pos
=
find
(
p
+
1
,
q
,
toFind
);
if
(
pos
!=
q
)
{
res
.
push_back
({
*
p
,
toFind
,
*
q
});
}
if
(
toFind
<
0
)
{
auto
pre_q
=
q
-
1
;
while
(
pre_q
!=
p
&&
(*
pre_q
==
*
q
))
{
--
pre_q
;
}
q
=
pre_q
;
}
//对于toFind==0情况,讨论不足。
else
{
auto
pre_p
=
p
+
1
;
while
(
pre_p
!=
q
&&
(*
pre_p
==
*
p
))
{
++
pre_p
;
}
p
=
pre_p
;
}
}
return
res
;
}
错误用例
Input:[-2,0,1,1,2]
Output:[[-2,0,2]]
Expected:[[-2,0,2],[-2,1,1]]
2
、别人的程序
使用
Two-pointers tech
,可以通过。
vector
<
vector
<
int
>
>
threeSum
(
vector
<
int
>
&
num
)
{
vector
<
vector
<
int
>
>
res
;
std
::
sort
(
num
.
begin
(),
num
.
end
());
for
(
int
i
=
0
;
i
<
num
.
size
();
i
++)
{
int
target
=
-
num
[
i
];
int
front
=
i
+
1
;
int
back
=
num
.
size
()
-
1
;
while
(
front
<
back
)
{
int
sum
=
num
[
front
]
+
num
[
back
];
// Finding answer which start from number num[i]
if
(
sum
<
target
)
front
++;
else
if
(
sum
>
target
)
back
--;
else
{
vector
<
int
>
triplet
(
3
,
0
);
triplet
[
0
]
=
num
[
i
];
triplet
[
1
]
=
num
[
front
];
triplet
[
2
]
=
num
[
back
];
res
.
push_back
(
triplet
);
// Processing duplicates of Number 2
// Rolling the front pointer to the next different number forwards
while
(
front
<
back
&&
num
[
front
]
==
triplet
[
1
])
front
++;
// Processing duplicates of Number 3
// Rolling the back pointer to the next different number backwards
while
(
front
<
back
&&
num
[
back
]
==
triplet
[
2
])
rear
--;
}
}
// Processing duplicates of Number 1
while
(
i
+
1
<
num
.
size
()
&&
num
[
i
+
1
]
==
num
[
i
])
i
++;
}
return
res
;
}
比较简短版的
vector
<
vector
<
int
>>
threeSum
(
vector
<
int
>&
nums
)
{
vector
<
vector
<
int
>>
triples
;
triples
.
reserve
(
200
);
sort
(
nums
.
begin
(),
nums
.
end
());
int
i
=
0
,
last
=
nums
.
size
()
-
1
;
while
(
i
<
last
)
{
int
a
=
nums
[
i
],
j
=
i
+
1
,
k
=
last
;
while
(
j
<
k
)
{
int
b
=
nums
[
j
],
c
=
nums
[
k
],
sum
=
a
+
b
+
c
;
if
(
sum
==
0
)
triples
.
push_back
({
a
,
b
,
c
});
if
(
sum
<=
0
)
while
(
nums
[
j
]
==
b
&&
j
<
k
)
j
++;
if
(
sum
>=
0
)
while
(
nums
[
k
]
==
c
&&
j
<
k
)
k
--;
}
while
(
nums
[
i
]
==
a
&&
i
<
last
)
i
++;
}
return
triples
;
}