三数之和与三元组最短距离

目录

题目一

解法一

解法二

题目二

解法一

解法二


题目一

链接:https://leetcode-cn.com/problems/3sum

给定一个包含 n 个整数的数组 nums,
判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?
找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组。

例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为:
[[-1, 0, 1],[-1, -1, 2]]

解法一

利用三层循环,暴力找出所有可能性,但会返回重复的三元组;时间复杂度O(n^3)。

该解法时间复杂度高是因为它寻找三个数,每次寻找就需要遍历一次数组。

对于式子a + b + c = 0,我们将式子改造成b + c = -a 的样式,这样他就类似于“两数之和”的形式:

假设已知a的值,如果知道了b的值,c的值自然而然就能得到。

这样a的值遍历一次,b和c只需遍历一次,两次遍历,时间复杂度为O(n^2)。

解法二

正向排序,再设置三个指针i、L、R,i用来遍历,L指向i + 1,R指向nums.size() - 1。L和R分别向中间靠拢,查找适合条件的元素。

如何决策呢?令sum = nums[i] + nums[L] + nums[R]。

如果 sum == 0 : 保存三元组,并令R--,L++;

如果 sum > 0 : 说明指针R指向的值太大了,令R--;

如果 sum < 0 :同理L指向的值太小了, L++;

如果 L>= R : i++;

如何去重呢?举个例子

[-4, -4, -1, -1, 0, 5, 5]

当i指向第一个“-4”,L指向第一个“-1”,R指向第二“5”,符合题干要求,L和R向内收缩,会得到与之前相同的结果;i++后依然能得到相同结果。

因此每个指针都需要跳过相同的元素。

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort( nums.begin(), nums.end());
        vector<vector<int>> res;
          for( int i = 0; i < nums.size(); i++){
            if( i > 0 && nums[i] == nums[i-1])
                continue;
            
            int L = i + 1, R = nums.size() - 1;
            while( l < r){
                int sum = nums[i] + nums[L] + nums[R];
                if( sum == 0){
                    vector<int> temp = { nums[i] , nums[L] , nums[R]};
                    res.push_back( temp);
                    
                    while( L<R && nums[L]==nums[L+1])L ++ ;
                    while( L<R && nums[R]==nums[R-1])R -- ;
                    
                    L ++ ;
                    R -- ;
                }
                else if( sum > 0)
                    R -- ;
                else if( sum < 0)
                    L ++ ;
            }
        }
        return res;
    }
};

题目二

定义三元组(a,b,c)(a,b,c均为整数)的距离D =∣a−b∣+∣b−c∣+∣c−a∣。
给定3个非空整数集合S1,S2和S3,按升序分别存储在3个数组中。
请设计一种尽可能高效的算法,计算并输出所有可能的三元组(a,b,c)(a∈S1,b∈S2,c∈S3)中的最小距离

例如,S1={-1, 0, 9},S2={-25, -10, 10, 11},S3={2, 9, 17, 30, 41},
则最小距离为2,相应的三元组为(9, 10, 9)。

解法一

依然是暴力求解,遍历三次,时间复杂度为O(三个数组长度之积)。

根据绝对值的定义:“|b-a|或|a-b|表示数轴上表示a的点和表示b的点的距离。”可知D的值等于ab点的距离+bc点的距离+ac点的距离。

解法二

我们假设a < b < c,画一条数轴:

 此时D的值为2倍的ac距离,如果能让a向c处移动,就能够减少D的值。

因此我们要找出三元组中最小的那一个元素,让它变大,然后再比较大小,重复此过程直至遍历完三个数组。时间复杂度为O(三个数组长度之和)。

#include<bits/stdc++.h>

using namespace std;

int isMin(int x, int y, int z){
	if(x <= y && x <= z)
		return 1;
	else 
		return 0;
}

int main(){
	int S1[] = {-1,0,9};
	int S2[] = {-25, -10, 10, 11};
	int S3[] = {2, 9, 17, 30, 41};
	int res[3] = {0, 0, 0};
	
	int Length1 = sizeof(S1)/sizeof(S1[0]);
	int Length2 = sizeof(S2)/sizeof(S2[0]);
	int Length3 = sizeof(S3)/sizeof(S3[0]);


	int D = INT_MAX; 
	int i = 0, j = 0, k = 0; 
	while(i < Length1 && j < Length2 && k < Length3 && D > 0){
		int dis = abs(S1[i] - S2[j]) + abs(S2[j]- S3[k]) + abs(S3[k] - S1[i]);
		if(dis < D){
			 D = dis;
			 res[0] = S1[i];
			 res[1] = S2[j];
			 res[2] = S3[k];
		}
		if(isMin(S1[i],S2[j],S3[k])) i++;
		else if(isMin(S2[j],S3[k],S1[i])) j++;
		else k++;
	}
	
	cout << res[0] << " " << res[1] << " " << res[2] << " " << endl;
	
	printf("最小距离是 %d", D);		
	
	return 0;
}

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DDD_duck

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值