1.1_Two_Sum
题目要求
Given an array of integers, return indices of the two numbers such that they add up to a specific target.You may assume that each input would have exactly one solution, and you may not use the same element twice.
转义:
给一个整型数组,从该数组找找到两个数,使得这两个数的和等于给定数值target,返回这个两个数在数组中的下标。同一个元素只能使用一次,并且对每一次给定的数组和target都会有解。
整体思路:
1.需要返回元素的下标,同时还需要根据元素的值计算是否等于target,所以我采用map来进行存储,map的key来存储该元素,value存储该元素在数组中的下标。
2.如果当前正在访问的元素能和map集合中的元素加起来等于target那么就可以直接返回该元素的下标与map集合中元素的value。
3.如果当前元素不能和map中的元素和起来等于target,那么就让当前元素也加入到map中成为备选项。此时如果map中的元素和当前要加入的元素的值相同,那也没有关系,因为题目就需要找一组和为target的元素下标。
代码:
public class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer,Integer> map=new HashMap<>();
int[] result=new int[2];
for(int i=0;i<nums.length;i++)
{
int another=target-nums[i];
if(map.get(another)!=null)
{
result[0]=i;
result[1]=map.get(another);
}
map.put(nums[i], i);
}
return result;
}
}
该问题分类:
数组问题-》数组元素求和问题-》寻找数组中和为target的数的下标
2.15_3Sum
题目要求:
Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note:
The solution set must not contain duplicate triplets.
转义:
给出一个整型数组,寻找数组中三个元素,使他们的和为0.返回含这样3个元素的集合。该集合中可能有多个三元组,但是每个三元组中的元素构成不能相同。
整体思路:
1.与上面Two sum相似,利用循环遍历数组,假定每一个元素都有可能是三元组中的一员。
2.然后从剩下的数组元素中查找是否存在两个元素使其和为上面找出来的元素的相反数。
代码:
public class Solution {
private List<List<Integer>> re=new ArrayList<>();
public List<List<Integer>> threeSum(int[] nums) {
//对数组进行排序
Arrays.sort(nums);
for(int i=0;i<nums.length;i++)
{
if(i==-1||nums[i]-nums[i-1]!=0)
{
helper(nums,-nums[i],i);
}
}
return re;
}
//一个Tow sum 寻找数组nums[i+1...n]中是否存在两个数使得这两个数的和为target
private void helper(int[] nums,int target,int j)
{
Integer tmp=null;
//不需要记录数组下标,只需要记录元素的值
Set<Integer> set=new HashSet<>();
for(int i=j+1;i<nums.length&&i!=j;i++)
{
int x=target-nums[i];
if(set.contains(x)&&(tmp==null||tmp!=nums[i]))
{
re.add(Arrays.asList(x,nums[i],nums[j]));
tmp=nums[i];
}
set.add(nums[i]);
}
}
}
出现的问题:
如何去重。
方法一:将已经找到的所有三元组存储起来。如果在出现新的三元组,和存储起来的所有的三元组进行对比,看是否会重复。(显然很浪费时间,而且实现起来很费力)
方法二:先将数组进行排序,如果当前的正在进行比较的元素与下一个元素相同,则跳过下一个元素。
该问题分类:
寻找数组中的元素使其和等于给定值
学习Disscuss中其他的方案:
思路:
外层循环创造出target,里面用tow sum的方法找到两个元素的和为target。
去重复:先将给定数组进行排序,然后跳过相同元素。
代码:
public class Solution {
public List<List<Integer>> threeSum(int[] num) {
Arrays.sort(num);
List<List<Integer>> res = new LinkedList<>();
for (int i = 0; i < num.length - 2; i++) {
if (i == 0 || (i > 0 && num[i] != num[i - 1])) {
int lo = i + 1, hi = num.length - 1, sum = 0 - num[i];
while (lo < hi) {
if (num[lo] + num[hi] == sum) {
res.add(Arrays.asList(num[i], num[lo], num[hi]));
while (lo < hi && num[lo] == num[lo + 1])
lo++;
while (lo < hi && num[hi] == num[hi - 1])
hi--;
lo++;
hi--;
} else if (num[lo] + num[hi] < sum)
lo++;
else
hi--;
}
}
}
return res;
}
}
3.18_4Sum
题目要求
Given an array nums of n integers and an integer target,are there elements a, b, c, and d in nums such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.
Note:The solution set must not contain duplicate quadruplets.
转义:
遇上面的3Sum基本相同,只不过该题是寻找4个元素,这4个元素的和为给定值target
整体思路:
1.该题我并没有向上面一样,外层循环创造出target,然后里面套3Sum,再套2Sum这样的解决方案。因为我认为这样写代码量会比较大,也相对来说更复杂(当时做题的时候确实是这样想的,但是后来看了Disscuss,也觉得这种办法可行,并且执行时间很快,比我这个快多了- -)。
2.所以我才用递归的方式来完成这倒题,主要的递归函数就是helper,我对该函数的定义为从nums[i+1...n]中寻找k个数,使得这k个数的和为target,并把这k个数存放到subRe集合中。
3.递归终止条件:当k等于0时表示已经找到了k个数,如果此时target刚好也为零,则说明k个数的和等于target,就可以将这组数加入到结果集中,并向下继寻找。如果target不为0,则说明这k个数的和不等于target。则需要继续进行寻找。
4.所以不管找到的k个数,是不是和为target都需要换新的数继续寻找,所以在最后直接return退出掉本次递归操作,再继续寻找新的元素。于此同时在结束掉递归的时候需要一个回溯操作将,subRe集合中的最后次加入的元素踢掉,换新的元素。
5.当整个递归结束掉的时候,也就寻找到符合条件的结果集了。
6.这个递归算法不仅适用于4Sum同时也适用于KSum,只需要修改其中的一些参数即可。
代码:
public class Solution {
private List<List<Integer>> re=new ArrayList<>();
public List<List<Integer>> fourSum(int[] nums, int target) {
Arrays.sort(nums);
int max=nums[nums.length-1];
int min=nums[0];
if(max*4<target)
{
return re;
}
if(min*4>target)
{
return re;
}
for(int i=0;i<nums.length;i++)
{
ArrayList<Integer> subRe = new ArrayList<>();
subRe.add(nums[i]);
helper(nums,i,3,target-nums[i],subRe);
while(i+1<nums.length&&nums[i]==nums[i+1])
{
i++;
}
}
return re;
}
//从nums[i+1...n]中找k个数使得和为target
private void helper(int[] nums, int i, int k, int target, ArrayList<Integer> subRe) {
if(k==0)
{
if(target==0) {
ArrayList<Integer> arrayList = new ArrayList<Integer>();
for(int j=0;j<subRe.size();j++)
{
arrayList.add(subRe.get(j));
}
re.add(arrayList);
}
return;
}
//加了这个时间上就通过了 - -
if(nums[i]*k>target)
{
return;
}
for(int j=i+1;j<nums.length;j++)
{
subRe.add(nums[j]);
helper(nums,j,k-1,target-nums[j],subRe);
subRe.remove(Integer.valueOf(nums[j]));
while(j+1<nums.length&&nums[j]==nums[j+1])
{
j++;
}
}
}
出现的问题:
1.list集合是引用类型,当我将sublist集合加入到result集合中。当sublist中的值发生改变之后result中的值也会发生变化。所以我之后在创建一个新的list将sublist中的值添加到新的list中然后再将新的list添加到result中- -。
2.时间超限
对这个递归树进行剪枝。即加入一些判断条件,减少进行一些无意义的递归次数或操作。
该问题分类:
寻找数组中的元素,使其和为给定值target。