1.两数之和
使用map集合,来减少时间复杂度;
public class TwoNumSum{
public static int[] twoSum(int[] nums,int target){
//集合中记录的是之前出现过的值,和当时该值的下标
Map<Integer,Integer> map =new HashMap<>();
for(int i=0;i<nums.length;i++){
// 如果map中记录有当前的target-nums[i],那么就找到了一组数据满足a+b=target;只需要从map中取出记录的a的下标以及当前值b的下标i,返回即可;
if(map.containsKey(target-nums[i])){
return new int[]{map.get(target-nums[i]),i};
}else{
// 说明map中还没有添加过当前下标所对应的值,需要进行记录,用于后续比较
map.put(nums[i],i);
}
}
return new int[0];
}
}
2.三数之和
使用排序+双指针
将无序数组排好序的目的是为了让碰撞双指针的移动方向更加明确,也方便去重;
public static List<List<Integer>> sumOfThreeNums(int[] nums) {
if (nums.length < 3) {
return new ArrayList<>();
}
// 使用util包下默认的排序(快排)
Arrays.sort(nums);
// 返回结果集合
List<List<Integer>> resList = new ArrayList<>();
for (int i = 0; i < nums.length; i++) {
// 如果当前的选定的数字已经大于0,说明该下标之后的数字全部是大于0的,所以不可能出现三数之和为0的情况;
if (nums[i] > 0) {
break;
}
// 如果当前数和前一个数相同,那么直接跳过
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
// 定义碰撞双指针
int left = i + 1;
int right = nums.length - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
// 如果三数之和等于0
if (sum == 0) {
// 先在返回结果集合中添加一条新的集合数据;
resList.add(Arrays.asList(nums[i], nums[left], nums[right]));
// 去重,如果数组出现这种情况(-1,-1,-1,0,2,2,2)不去重很有可能会记录相同的结果,不符合题意
while (left < right && nums[left] == nums[left + 1]) left++;
while (left < right && nums[right] == nums[right - 1]) right--;
//不管是去重后,还是本来就不用去重,都需要left++,right--,改变指针;
left++;
right--;
} else if (sum < 0) { //如果sum<0 说明nums[left]还太小,需要left往后移,使nums[left]变大
left++;
} else { // 如果sum > 0 说明nums[right] 太大了,需要right往前移,使nums[right]减小
right--;
}
}
}
return resList;
}