三数之和

本文深入探讨了“三数之和”问题的多种解决策略,包括暴力求解、使用hashmap以及一种类似快速排序的方法。通过对不同方法的时间复杂度和效率的分析,最终提供了一种在LeetCode上表现优异的解决方案。

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

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

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

满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
2.方法一,暴力求解:

package algorithm;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.InputMismatchException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

public class ThreeSum2 {
	public static void main(String args[]) {
		int temp,target;
		ArrayList arraylist = new ArrayList();
		Scanner reader = new Scanner(System.in);
		System.out.println("请输入一个数组,按回车键结束:");
		String s = reader.nextLine();
		Scanner reader2 = new Scanner(s);
		//以下将字符转换回整数存入数组(将数字抽取出来)
		while(reader2.hasNext()) {
			try {
				int num=reader2.nextInt();
				arraylist.add(num);
			}catch(InputMismatchException exp) {
				String t=reader2.next();
			}
		}
		//将arraylist转换为int[]型数组,以便和参数相对应;
		int [] intArray = new int[arraylist.size()];
		for(int i=0;i<arraylist.size();i++) {
			intArray[i]=(int) arraylist.get(i);
		}
		List<List<Integer>> result = new ArrayList<>();
		
		Solution obj = new Solution();
		result = obj.threeSum(intArray);
		System.out.println("返回结果:");
		System.out.println("[  ");
		/*
		 * 重新构造一个int[]数组,用toString进行输出;构造过程跟上面将arraylist转换int[]数组一样,for循环;
		 */
		int [] array;
		for (int i = 0; i < result.size(); i++) {
			array = new int[result.get(i).size()];
			for (int j = 0; j < result.get(i).size(); j++) {
				array[j] = (int) result.get(i).get(j);
			}
			if (i != result.get(i).size() - 1) {
				System.out.println(Arrays.toString(array) + ',');
			} else {
				System.out.println(Arrays.toString(array));
			}
		}
		System.out.println(" ]");
	}
}

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
    	int n=0;
        List<List<Integer>> list2 = new ArrayList<>();
    	for(int i=0;i<nums.length;i++) {
    		for(int j=0;j<nums.length;j++) {
    			if(j==i) {
    				continue;
    			}
    			for(int k=0;k<nums.length;k++) {
    				if(k==i||k==j) {
    					continue;
    				}
					if (nums[i] + nums[j] + nums[k] == 0) {
						List<Integer> list1 = new LinkedList<>();
						list1.add(nums[i]);
						list1.add(nums[j]);
						list1.add(nums[k]);
						Collections.sort(list1);
						if (!list2.contains(list1)) {
							list2.add(list1);
						}
					}
    			}
    		}
    	}
    	return list2;
    }
}

执行结果如下:
在这里插入图片描述
方法二:使用hashmap,时间复杂度O(n2):

package algorithm;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.InputMismatchException;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

public class ThreeSum4 {
	public static void main(String args[]) {
		int temp,target;
		ArrayList arraylist = new ArrayList();
		Scanner reader = new Scanner(System.in);
		System.out.println("请输入一个数组,按回车键结束:");
		String s = reader.nextLine();
		Scanner reader2 = new Scanner(s);
		//以下将字符转换回整数存入数组(将数字抽取出来)
		while(reader2.hasNext()) {
			try {
				int num=reader2.nextInt();
				arraylist.add(num);
			}catch(InputMismatchException exp) {
				String t=reader2.next();
			}
		}
		//将arraylist转换为int[]型数组,以便和参数相对应;
		int [] intArray = new int[arraylist.size()];
		for(int i=0;i<arraylist.size();i++) {
			intArray[i]=(int) arraylist.get(i);
		}
		List<List<Integer>> result = new ArrayList<>();
		
		Solution obj = new Solution();
		result = obj.threeSum(intArray);
		System.out.println("返回结果:");
		System.out.println('[');
		/*
		 * 重新构造一个int[]数组,用toString进行输出;构造过程跟上面将arraylist转换int[]数组一样,for循环;
		 */
		int [] array;
		for (int i = 0; i < result.size(); i++) {
			array = new int[result.get(i).size()];
			for (int j = 0; j < result.get(i).size(); j++) {
				array[j] = (int) result.get(i).get(j);
			}
			if (i != result.get(i).size() - 1) {
				System.out.println(Arrays.toString(array) + ',');
			} else {
				System.out.println(Arrays.toString(array));
			}
		}
		System.out.println(']');
	}
}

class Solution{
    public List<List<Integer>> threeSum(int[] nums) {
    	Integer comp;
        Map<Integer,Integer> map = new HashMap<>();
        Map<List,Integer> map2 = new HashMap<>();
        List<List<Integer>> list2 = new ArrayList<>();
        //将数组每个元素出现的个数以键值对的形式记录在map
        for(int i=0;i<nums.length;i++) {
        	Integer num = map.get(nums[i]);
        	map.put(nums[i], num==null? 1: num+1);
        }
        Arrays.sort(nums);
        for(int i=0;i<nums.length-1;i++) {
        	for (int j = i + 1; j < nums.length-1; j++) {
        		int complement = -nums[i] - nums[j];
				comp = Integer.valueOf(complement);
				if(map.containsKey(comp)) {
					if(complement==nums[i]||complement==nums[j]) {
						//如果是0,必须出现3个以上
						if(complement==0) {
							if(map.get(comp).intValue()<3) {
								continue;
							}
						}else {
							if(map.get(comp).intValue()<2) {
								continue;
							}
						}
					}
					List<Integer> list1 = new ArrayList<>();
					list1.add(nums[i]);
					list1.add(nums[j]);
					list1.add(complement);
					Collections.sort(list1);//[-1,1]和[1,-1]是不一样的,所以需排序使它们一样,便于后面排除,解决了三元组重复问题
					if (!list2.contains(list1)) {
						list2.add(list1);
					}	
				}
			}
        }
        return list2;
    }
}

测试结果:
在这里插入图片描述
在这里插入图片描述
以上两种方法有弊端,方法一太不值得提倡了,O(n3)的时间复杂度基本可以丢弃了,方法二的话虽说压缩到O(n2),但当遇到有许多重复元素的数组时,不能去除不必要的运算。且方法二leetcode上还有2个例子没跑过,超出时间限制。下面贴出可以在leetcode上跑过的代码,别人的答案:

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> ls = new ArrayList<>();
 
        for (int i = 0; i < nums.length - 2; i++) {
            if (i == 0 || (i > 0 && nums[i] != nums[i - 1])) {  // 跳过可能重复的答案
 
                int l = i + 1, r = nums.length - 1, sum = 0 - nums[i];
                while (l < r) {
                    if (nums[l] + nums[r] == sum) {
                        ls.add(Arrays.asList(nums[i], nums[l], nums[r]));
                        while (l < r && nums[l] == nums[l + 1]) l++;
                        while (l < r && nums[r] == nums[r - 1]) r--;
                        l++;
                        r--;
                    } else if (nums[l] + nums[r] < sum) {
                        while (l < r && nums[l] == nums[l + 1]) l++;   // 跳过重复值
                        l++;
                    } else {
                        while (l < r && nums[r] == nums[r - 1]) r--;
                        r--;
                    }
                }
            }
        }
        return ls;
    }
}

有点类似于快速排序算法吧,自己对快速排序不是很了解,没想到这种方法。

后记:这道题也折腾了好几天,当然是断断续续,主要是对java的map,list,set,hashcode等理解不深,用的过程出了很多错误,不过通过这道题也对这些容器的用法也有所了解了。

内容概要:本文档是份关于交换路由配置的学习笔记,系统地介绍了网络设备的远程管理、交换机与路由器的核心配置技术。内容涵盖Telnet、SSH、Console三种远程控制方式的配置方法;详细讲解了VLAN划分原理及Access、Trunk、Hybrid端口的工作机制,以及端口镜像、端口汇聚、端口隔离等交换技术;深入解析了STP、MSTP、RSTP生成树协议的作用与配置步骤;在路由部分,涵盖了IP地址配置、DHCP服务部署(接口池与全局池)、NAT转换(静态与动态)、静态路由、RIP与OSPF动态路由协议的配置,并介绍了策略路由和ACL访问控制列表的应用;最后简要说明了华为防火墙的安全区域划分与基本安全策略配置。; 适合人群:具备定网络基础知识,从事网络工程、运维或相关技术岗位1-3年的技术人员,以及准备参加HCIA/CCNA等认证考试的学习者。; 使用场景及目标:①掌握企业网络中常见的交换与路由配置技能,提升实际操作能力;②理解VLAN、STP、OSPF、NAT、ACL等核心技术原理并能独立完成中小型网络搭建与调试;③通过命令示例熟悉华为设备CLI配置逻辑,为项目实施和故障排查提供参考。; 阅读建议:此笔记以实用配置为主,建议结合模拟器(如eNSP或Packet Tracer)动手实践每条命令,对照拓扑理解据流向,重点关注VLAN间通信、路由选择机制、安全策略控制等关键环节,并注意不同设备型号间的命令差异。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值