编程题:两数之和&数组中相加为0的三元数组
两数之和
给出一个整数数组,请在数组中找出两个加起来等于目标值的数,
你给出的函数twoSum 需要返回这两个数字的下标(index1,index2),需要满足 index1 小于index2.。注意:下标是从1开始的
假设给出的数组中只存在唯一解
例如:
给出的数组为 {20, 70, 110, 150},目标值为90
输出 index1=1, index2=2
数组中相加为0的三元数组
给出一个有n个元素的数组S,S中是否有元素a,b,c满足a+b+c=0?找出数组S中所有满足条件的三元组。
注意:
- 三元组(a、b、c)中的元素必须按非降序排列。(即a≤b≤c)
- 解集中不能包含重复的三元组。
例如,给定的数组 S = {-10 0 10 20 -10 -40},解集为(-10, 0, 10) (-10, -10, 20)
思路
之所以将两道题目放在一起讲,主要时因为当初这两道题给了我很强的既视感,两个题目解题思路相互影响,导致了我走向了两个错误的方向,每一道题都走错了。
两数之和:第一反应是排序遍历,因为求和排序后会方便遍历,然而该题目需要返回的是下标,排序打乱顺序会影响结果,如果强行实现也会多出许多用来记录原位置的开销。那么放弃了排序的算法,使用map以记录(数值,下标),每次遍历前判断是否存在target-当前值的值在map中,有则取出并返回下标。
数组中相加为0的三元组:做到这个题的时候刚做完两数之和,脑子一下子没转过来,a+b+c=0不就是a+b=-c吗?然而这个题目不是唯一解,而且需要返回对的是三元组按非降序排列,而且不允许重复。所以排序后再遍历是一个很好的方法。
解题:两数之和
/** * * @param numbers int整型一维数组 * @param target int整型 * @return int整型一维数组 */ public int[] twoSum (int[] numbers, int target) { /*从数组中返回和是targe的两个数的下标,假设有值且唯一,下标从1起算*/ Map<Integer,Integer> map= new HashMap<>(); //PrintIntArray(numbers); for(int i=0;i<numbers.length;i++){ if(map.containsKey(target-numbers[i])){ return new int[]{map.get(target-numbers[i])+1,i+1}; } map.put(numbers[i],i); } return new int[]{-1,-1}; }
解题:数组中相加为0的三元数组
public ArrayList<ArrayList<Integer>> threeSum(int[] num) { ArrayList<ArrayList<Integer>> res = new ArrayList<>(); /*先排序*/ sort(num); for(int i=0;i<num.length;){ if(num[i]>0) break; //优化 for(int j=i+1;j<num.length;){ if(num[i]+num[j]>0) break; for(int k=j+1;k<num.length;){ if(num[i]+num[j]+num[k]>0){ break; //优化 } if(num[i]+num[j]+num[k]==0){ ArrayList<Integer> alist = new ArrayList<>(); alist.add(num[i]); alist.add(num[j]); alist.add(num[k]); res.add(alist); break; } int temp = num[k]; while (k<num.length&&num[k]==temp){//跳过重复项 k++; } } int temp = num[j]; while (j<num.length&&num[j]==temp){//跳过重复项 j++; } } int temp = num[i]; while (i<num.length&&num[i]==temp){//跳过重复项 i++; } } return res; }
当你深入了解,你就会发现世界如此广袤,而你对世界的了解则是如此浅薄,请永远保持谦卑的态度。