前言:
大家好,今天是LeetCode每日一题的第六天,给大家分享的是 无序数组–两数之和,难度系数一颗星!废话不多数,先上题目!
1.1 题目要求
题目类型:两数之和
题目内容:给定一个整数数组 numbers,从数组中找出两个数满足相加之和等于目标数target
注意事项:
- 假设每个输入只对应唯一的答案,而且不可以重复使用相同的元素
- 返回两数的下标值,以数组形式返回
1.2 解题方法
1.2.1 使用暴力算法
1.解题思路
题干分析:
- 假设存在一个整型数组nums,假设数组中存在两个元素:nums[i]和nums[j],满足从数组中找出两个数满足相加之和等于目标数target,即nums[i] + nums[j] = target;
初始状态:[0, 1, 2, 3, ... , n-1]
i j
某一时刻: [0, 1, 2, 3, ... , n-1]
i + j = target
- 题干中要求不可以重复使用相同的元素,即nums[i]和nums[j]不能为同一个元素,或者说 i 下标不等于 j下标;
- 题干中还要求返回两数的下标值,以数组形式返回,即返回值为 [i,j]
2.代码实现
- 测试代码
package com.kuang.leetcode7;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName TwoNumbersSum1
* @Description 计算两数之和--无序数组
* @Author 狂奔の蜗牛rz
* @Date 2021/8/19
*/
public class TwoNumbersSum1 {
//主方法测试
public static void main(String[] args) {
//初始化整型数组元素
int[] arr = {1,3,5,2,4,6};
//预估结果: 4+6=10, 返回值为4,5 (使用Arrays数组工具类的toString方法将返回值转换为字符串形式)
System.out.println("暴力算法测试结果:"+ Arrays.toString(solution1(arr,10))); //测试结果: [4,5]
}
/**
* 求两数之和 第一版
* @param nums 整型数组
* @param target 目标值
* @return
*/
public static int[] solution1(int[] nums, int target) {
//外层循环遍历
for (int i = 0; i < nums.length; i++) {
//内层循环遍历
// for(int j = 1; j < nums.length; j++) {
/**
* 第一轮循环: [0, 1, 2, 3, ..., n-1]
* 外层循环: i->
* 内层循环: j->
* 第二轮循环: [0, 1, 2, 3, ..., n-1]
* 外层循环: i ->
* 内层循环: j ->
* 由于第二轮外层循环i从1开始, 而j的初值为1, 所以第二轮内层循环初始位置也是1,
* 这样就出现两个指针位置重合的情况, 即本轮循环中j下标会走i下标走过的值,
* 解决方案:
* 为了保证两者不重合, 降低算法计算次数, 可以将j初值赋值为i+1, 即 j = i + 1
*/
for(int j = i + 1; j < nums.length; j++) {
//判断i下标元素和j下标元素相加之和是否等于target目标值
if(nums[i] + nums[j] == target) {
//返回值为创建一个新的整型数组, 包含i和j下标
return new int[]{i,j};
}
}
}
//若target值不存在, 则返回值为一个元素值为0的整形数组
return new int[0];
}
}
- 测试结果
结果:与预测结果一致!
1.2.2 使用改进算法
1.解题思路
我们发现,需要确认i下标和j下标元素在数组中同时存在,这样才能保证target目标数存在, 但这样的时间复杂度为 O(n^2);
那怎样才能降低时间复杂度呢?
解决方案:
其实我们完全不必要同时验证i下标和j下标元素存在, 为什么这样说?
- 由于要满足 nums[i] + nums[j] == target条件,我们只需求出 target 和 num[i] 的差值是否存在,即验证 nums[j] 是否存在
2.代码实现
- 测试代码
package com.kuang.leetcode7;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName TwoNumbersSum1
* @Description 计算两数之和--无序数组
* @Author 狂奔の蜗牛rz
* @Date 2021/8/19
*/
public class TwoNumbersSum {
//主方法测试
public static void main(String[] args) {
//初始化整型数组元素
int[] arr = {1,3,5,2,4,6};
//预估结果: 4+6=10, 返回值为4,5 (使用Arrays数组工具类的toString方法将返回值转换为字符串形式)
System.out.println("改进算法测试结果:"+Arrays.toString(solution2(arr,10))); //测试结果: [4,5]
}
/**
* 求两数之和 第二版
* @param nums 整型数组
* @param target 目标值
* @return
*/
public static int[] solution2(int[] nums, int target) {
//创建一个key-value都为Integer类型的Map集合
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
//外层循环遍历
for (int i = 0; i < nums.length; i++) {
//判断map集合汇总是否包含target和nums[i]的差值的Key下标
/**
* 假设存在下面这样一个整型数组
* [1, 3, 5, 2, 4, 6]
* 初始状态: i->
* 指针右移: ------|----------->
* 遍历到5: i
* 指针右移: ----------------|-->
* 遍历到6: i
* 假设i指针遍历到元素5位置, target和nums[i]的差值就已存在,那么就结束遍历;
* 最坏情况也是遍历到元素6, 即把整个数组遍历一遍, 那么其时间复杂度为O(n)
*/
if(map.containsKey(target - nums[i])) {
/**
* 若map中Key值存在, 则返回一个新的整型数组,
* 其元素值为target和nums[i]的差值对应的value值和i下标
*/
return new int[]{map.get(target - nums[i]),i};
}
//若该轮遍历的i下标不符合条件, 将key值为nums[i], value值为i存入map集合中
map.put(nums[i], i);
}
//若map中的Key值不存在, 则返回值为一个元素值为0的整形数组
return new int[0];
}
}
- 测试结果
结果:与预测结果一致!
好了,今天LeetCode每日一题—无序数组–两数之和到这里就结束了,欢迎大家学习和讨论,点赞和收藏!
参考视频链接:https://www.bilibili.com/video/BV1Ey4y1x7J3 (国内算法宝典-LeetCode算法50讲)