相关的题解
leetcode 15 三数之和:给定一个数组nums
,找出数组里面三个数字之和为0的组合,组合不能重复 题解:先给数组排好序,然后固定最左边的数(i
)。然后在右边数组中找两个数字, 看是否满足情况,此时就运用到了双指针算法。
设置两个指针j,k
,j
指向i
右边的第一个数字(j=i+1
),k
另一个指向数组的最后一个数字k=nums.length-1
,分别代表三数中的中间值和最大值
如果此时nums[i]+nums[j]+nums[k]>0
说明k
太大了,执行k--
如果此时nums[i]+nums[j]+nums[k]<0
说明j
太小了,执行j++
如果找到了,那么将i,j,k
加入list
中 将i
向右移动一格,重复上述动作,直到i== nums.length-2
,就把所有的值都找到了 实现的过程中,需要注意组合去重,比如nums = [-1,-1,0,1]
这种,可以找到两个[-1,0,1]
这样的组合,这就会导致错误。
那要如何去重呢, 主要有两个部分 首先是针对i
的去重,我们不难发现,如果nums[i] = nums[i-1]
那么,当前的i
也没有必要再关注了,直接跳过即可 然后是针对j,k
的去重,因为是三数之和,不难知道这是知二得三的情况,因此只需要限制nums[j]
或者nums[k]
的情况即可 实现:
class Solution {
public List< List< Integer> > threeSum ( int [ ] nums) {
List< List< Integer> > list = new ArrayList < List< Integer> > ( ) ;
int n = nums. length;
if ( nums == null || n < 3 ) return list;
Arrays. sort ( nums) ;
for ( int i = 0 ; i < n- 2 ; i++ ) {
if ( i== 0 || nums[ i] != nums[ i- 1 ] ) {
int j = i+ 1 , k = n- 1 ;
while ( j < k) {
List< Integer> tmp_list = new ArrayList < Integer> ( ) ;
int tmp = nums[ i] + nums[ j] + nums[ k] ;
if ( tmp < 0 ) j++ ;
else if ( tmp > 0 ) k-- ;
else {
int prelow = nums[ j] ;
tmp_list. add ( nums[ i] ) ;
tmp_list. add ( nums[ j] ) ;
tmp_list. add ( nums[ k] ) ;
list. add ( tmp_list) ;
while ( j< k&& prelow== nums[ j] ) j++ ;
}
}
}
}
return list;
}
}
leetcode 16 最接近的三数之和:给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近,返回这三个数的和(每组输入只存在唯一答案) 题解:这个乍一看还以为很难,结果是换汤不换药,而且i,j,k
只有一组, 因此比较容易实现,只需要再维护一最小绝对距离dis
就可以完成操作。
class Solution {
public int threeSumClosest ( int [ ] nums, int target) {
int n = nums. length;
int dis = Integer. MAX_VALUE;
Arrays. sort ( nums) ;
int ans = nums[ 0 ] + nums[ 1 ] + nums[ 2 ] ;
for ( int i = 0 ; i < n- 2 ; i++ ) {
if ( i> 0 && ( nums[ i] == nums[ i- 1 ] ) ) continue ;
int j = i+ 1 , k = n- 1 ;
while ( j < k) {
int tmp = nums[ i] + nums[ j] + nums[ k] ;
if ( dis > Math. abs ( tmp- target) )
{
dis = Math. abs ( tmp- target) ;
ans = tmp;
}
if ( tmp < target)
j++ ;
else if ( tmp > target)
k-- ;
else return target;
}
}
return ans;
}
}
leetcode 259 较小的三数之和
题意:给定一个长度为 n 的数组nums
和一个目标值target
,寻找能够使条件 nums[i] + nums[j] + nums[k] < target 成立的三元组 i, j, k 个数。 题解:仍然是换汤不换药,没什么可介绍的了,唯一的改动就是在判断tmp<target
的时候,让结果计数器加上k-j
这么多(因为当i,j,k
满足条件的时候,k=j+1~k
都满足,因此总数是k-j
个) public int threeSumSmaller ( int [ ] nums, int target) {
int res = 0 ;
int n = nums. length;
Arrays. sort ( nums) ;
for ( int i = 0 ; i < n- 2 ; i++ ) {
int j = i+ 1 , k = n- 1 ;
while ( j < k) {
int tmp = nums[ i] + nums[ j] + nums[ k] ;
if ( tmp < target) {
res+= ( k- j) ;
j++ ;
}
if ( tmp >= target)
k-- ;
}
}
return res;
}
leetcode 923: 三数之和的多种可能,给定数组A
,和目标值target
,要求将A
中所有满足和为target
的三元组的数量找出来,将最后结果对1e9+7求模 题解:还是和三数之和的大体做法一样,但是因为要计算个数,这里最主要考虑的就是满足条件的重复组合的个数。其实就是遍历找到左边(j
)重复元素的个数与右边(k
)重复元素的个数,统计完之后就直接相乘就是答案。不过还有一种特殊情况,就是A[j]=A[k]
的时候,这说明[j,k]
中间所有元素都相同,那么遍历的话j
将会直接到达k
的位置,这时候乘法就没有用处了,正确个数是(k-j)+...+1
class Solution {
public int threeSumMulti ( int [ ] A, int target) {
int MOD = 1 _000_000_007;
long ans = 0 ;
Arrays. sort ( A) ;
for ( int i = 0 ; i < A. length; ++ i) {
int j = i+ 1 , k = A. length - 1 ;
while ( j < k) {
int tmp = A[ i] + A[ j] + A[ k] ;
if ( tmp < target)
j++ ;
else if ( tmp > target)
k-- ;
else if ( A[ j] != A[ k] ) {
int left = 1 , right = 1 ;
while ( j+ 1 < k && A[ j] == A[ j+ 1 ] ) {
left++ ;
j++ ;
}
while ( k- 1 > j && A[ k] == A[ k- 1 ] ) {
right++ ;
k-- ;
}
ans += left * right;
ans %= MOD;
j++ ;
k-- ;
} else {
ans += ( k- j+ 1 ) * ( k- j) / 2 ;
ans %= MOD;
break ;
}
}
}
return ( int ) ans;
}
}
相关题目