在算法问题中有一类十分常见的问题,就是求和,例如LeetCode开篇第一题——两数之和,以及第15题三数之和和第18题四数之和。下面我们就来仔细分析下这种题目的解法以及套路。

两数之和



java8 一个数组从另一个数组中过滤_数组

LeetCode1.两数之和

    题目很简单,就是求数组中那两个数之和和目标数一致。第一个涌现出来的想法就是很简单的直接暴力求解,两层for循环搞定。这种方法相对无脑,但是肯定不是最优解法,最优解法就是

解法(哈希表)
class Solution {
    public int[] twoSum(int[] nums, int target) {
        // 输出格式
        int [] ans = new int[2];
        // map用于存放数组,便于查询
        HashMap map = new HashMap<>();// 将数组的值和索引变为key-value存放起来,顺便查看现在的map中是否有符合情况的。for(int i=0;i            if(map.containsKey(target-nums[i])){
                ans[0]=i;
                ans[1]=map.get(target-nums[i]);return ans;
            }map.put(nums[i],i);
        }return ans;
    }
}

    两数之和相对来说简单一些,就是利用到hashmap查询快的原理来进行解决,在插入的同时顺便查询是否有符合条件的选项,防止后面无谓的插入以及再通过一个foe循环进行查找。

三数之和



java8 一个数组从另一个数组中过滤_List_02

LeetCode15.三数之和

    根据上面两数之和的思路,我们这次还是采用哈希表来进行优化求解,首先我们先将数组排序,然后将有序数组放入hash表中,然后我们通过两层遍历,确定好前两个数字然后再去寻找hash表中是否存在满足和为0的数据即可。

解法(哈希表)
class Solution {
    public List> threeSum(int[] nums) {
        Arrays.sort(nums);
        HashMap map =new HashMap<>();
        List> ans =new ArrayList<>();// 将有序的数组存入map中for(int i=0; i            map.put(nums[i],i);
        }int target =0;for(int i=0;i            target=-nums[i];// 去重 防止出现多个连续的值从而出现多个一样的答案if(i>0&&nums[i]==nums[i-1]){continue;
            }for(int j=i+1;j                // 依旧去重if(j>i+1&&nums[j]==nums[j-1]){continue;
                }if(map.containsKey(target-nums[j])&&map.get(target-nums[j])>j){
                    ans.add(new ArrayList<>(Arrays.asList(nums[i],nums[j],target-nums[j])));
                }else{continue;
                }
            }
        }return ans;
    }
}

四数之和



java8 一个数组从另一个数组中过滤_java_03

LeetCode18.四数之和

    有了前面的经验,这次解决四数之和的思路和前面一样。因此我们先回顾一下,三数之和我们是如何求解的。首先是先固定一个数,然后转化为找两数之和等于目标值的问题。同样的四数之和我们只需要固定两个数,然后去找另外两个数,同样的需要去重,来防止重复。

    在这里我们用另外一种方法来解决,即不借助hashmap而使用指针来解决。

解法(双指针)
class Solution {
        public List<List> fourSum(int[] nums, int target) {// 一样的套路还是先排序
            Arrays.sort(nums);List<List> ans = new ArrayList<>();int len = nums.length;// 定位第一个数for (int i = 0; i                 // 去重if (i > 0 && nums[i] == nums[i - 1]) {continue;
                }for (int j = i + 1; j                     // 去重if (j > i + 1 && nums[j] == nums[j - 1]) {continue;
                    }int l = j + 1;int r = len - 1;while (l                         int sum = nums[i] + nums[j] + nums[l] + nums[r];if (sum == target) {
                            ans.add(new ArrayList<>(Arrays.asList(nums[i], nums[j], nums[l], nums[r])));// 去重while (l 1]) {
                                l++;
                            }while (l 1]) {
                                r--;
                            }// 继续找该情况(两个数固定)下是否还有答案
                            l++;
                            r--;
                        } else if (sum > target) {
                            r--;
                        } else {
                            l++;
                        }
                    }
                }
            }return ans;
        }
    }

总结

    经过这三道题的洗礼,我相信当你下次再面对N数之和题目时,你会轻轻松松的解决他们。其解决的核心思想就是化繁为简,将求多个数之和通过先固定几个数来降维到两数求和,最后就可以在哈希算法和双指针中选择一个你拿手的方法来解决。

    另外需要注意的一点就是去重,防止出现相同的答案。