一文秒殺三個經典面試求和問題

一文帶你秒殺三個求和問題php

今天爲你們帶來三道求和問題,經過文字,圖畫,動圖爲你們解析,很容易就能讀懂,每道題目都是經典題,你們快來打卡吧。java

題目來源:leetcode 1.兩數之和(簡單) 15.三數之和(中等) 18.四數之和(中等)git

兩數之和

題目描述:

給定一個整數數組 nums 和一個目標值 target,請你在該數組中找出和爲目標值的那 兩個 整數,並返回他們的數組下標。程序員

你能夠假設每種輸入只會對應一個答案。可是,數組中同一個元素不能使用兩遍。github

示例:算法

給定 nums = [2, 7, 11, 15], target = 9數組

由於 nums[0] + nums[1] = 2 + 7 = 9
因此返回 [0, 1]微信

題目很容易理解,即讓查看數組中有沒有兩個數的和爲目標數,若是有的話則返回兩數下標,咱們爲你們提供兩種解法雙指針(暴力)法,和哈希表法框架

哈希表

解析

哈希表的作法很容易理解,咱們只需經過一次循環便可,假如咱們的 target 值爲 9,當前指針指向的值爲 2 ,咱們只需從哈希表中查找是否含有 7,由於9 - 2 =7 。若是含有 7 咱們直接返回便可,若是不含有則將當前的2存入哈希表中,指針移動,指向下一元素。注: key 爲元素值,value 爲元素索引。spa

動圖解析:

兩數之和

是否是很容易理解,下面咱們來看一下題目代碼。

題目代碼:

class Solution {
    public int[] twoSum(int[] nums, int target) {
        HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();
        for(int i = 0; i < nums.length; i++){
            //若是存在則返回
            if(map.containsKey(target-nums[i])){
                return new int[]{map.get(target-nums[i]),i};
            }
            //不存在則存入
            map.put(nums[i],i);

        }
        return new int[0];

    }
}

雙指針(暴力)法

解析

雙指針(L,R)法的思路很簡單,L指針用來指向第一個值,R指針用來從第L指針的後面查找數組中是否含有和L指針指向值和爲目標值的數。見下圖

例:綠指針指向的值爲3,藍指針須要在綠指針的後面遍歷查找是否含有 target - 3 = 2的元素,若含有返回便可。

題目代碼

class Solution {
    public int[] twoSum(int[] nums, int target) {
        if(nums.length < 2){
            return new int[0];
        }
        int[] rearr = new int[2];
        //查詢元素
        for(int i = 0; i < nums.length; i++){
            for(int j = i+1; j < nums.length; j++ ){
                if(nums[i] + nums[j] ==target){
                    rearr[0] = i;
                    rearr[1] = j;
                }
            }
        }
        return rearr;
    }
}

三數之和

題目描述:

給你一個包含 n 個整數的數組 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?請你找出全部知足條件且不重複的三元組。

注意:答案中不能夠包含重複的三元組。

示例:

給定數組 nums = [-1, 0, 1, 2, -1, -4],

知足要求的三元組集合爲:
[
[-1, 0, 1],
[-1, -1, 2]
]

這個題目算是對剛纔題目的升級,剛纔題目咱們是隻需返回一個例子便可,可是這個題目是讓咱們返回全部狀況,這個題目咱們須要返回三個數相加爲 0 的全部狀況,可是咱們須要去掉重複的三元組(算是該題的核心),因此這個題目仍是挺有趣的,你們記得打卡呀。

哈希表:

解析

咱們這個題目的哈希表解法是很容易理解的,咱們首先將數組排序,排序以後咱們將排序過的元素存入哈希表中,咱們首先經過兩層遍歷,肯定好前兩位數字,那麼咱們只須要哈希表是否存在符合狀況的第三位數字便可,跟暴力解法的思路相似,很容易理解,可是這裏咱們須要注意的狀況就是,例如咱們的例子爲[-2 , 1 , 1],若是咱們徹底按照以上思路來的話,則會出現兩個解,[-2 , 1 , 1]和[1 , 1, -2]。具體緣由,肯定 -2,1以後發現 1 在哈希表中,存入。肯定 1 ,1 以後發現 -2 在哈希表中,存入。因此咱們須要加入一個約束避免這種狀況,那就是咱們第三個數的索引大於第二個數時才存入。

640

上面這種狀況時是不能夠存入的,由於咱們雖然在哈希表中找到了符合要求的值,可是 -2 的索引爲 0 小於 2 因此不能夠存入。

題目代碼

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
       if(nums.length < 3){
           return new ArrayList<>();
       }
       //排序
       Arrays.sort(nums);
       HashMap<Integer,Integer> map = new HashMap<>();
       List<List<Integer>> resultarr = new ArrayList<>();
       //存入哈希表
       for(int i = 0; i < nums.length; i++){
           map.put(nums[i],i);
       }
       Integer t;
       int target = 0;
       for(int i = 0; i < nums.length; ++i){            
            target = -nums[i];
            //去重
            if(i > 0 && nums[i] == nums[i-1]){
                continue;
            }
            for(int j = i + 1; j < nums.length; ++j){
                if(j > i+1 && nums[j] == nums[j-1]){
                    continue;
                }             
                if((t = map.get(target - nums[j])) != null){
                    //符合要求的狀況,存入
                    if(t > j){                      
                       resultarr.add(new ArrayList<>
                       (Arrays.asList(nums[i], nums[j], nums[t])));

                    } 
                    else{
                        break;
                    }                                                  
                }
            }
       }
       return resultarr;
    }
}

多指針

解析:

若是咱們將上個題目得指針解法稱作是雙指針的話,那麼這個題目用到的方法就是三指針,由於咱們是三數之和嘛,一個指針對應一個數,下面咱們看一下具體思路,其實原理很簡單,咱們先將數組排序,直接 Arrays.sort() 解決,排序以後處理起來就很容易了。下面咱們來看下三個指針的初始位置。

三數之和起始

初始狀況見上圖,咱們看當前狀況,三數之和爲 -3 ,很顯然不是 0 ,那麼咱們應該怎麼作呢?

咱們設想一下,咱們當前的三數之和爲 -3 < 0 那麼咱們若是移動橙色指針的話則會讓咱們的三數之和變的更小,由於咱們的數組是有序的,因此咱們移動橙色指針(藍色不動)時和會變小,若是移動藍色指針(橙色不動)的話,三數之和則會變大,因此這種狀況則須要向右移動咱們的藍色指針,找到三數之和等於 0 的狀況進行保存,若是三數之和大於 0 的話,則須要移動橙色指針,途中有三數之和爲 0 的狀況則保存。直至藍橙兩指針相遇跳出該次循環,而後咱們的綠指針右移一步,繼續執行上訴步驟。可是這裏咱們須要注意的一個細節就是,咱們須要去除相同三元組的狀況,咱們看下面的例子。

三數之和舉例

這裏咱們發現 0 - 1 + 1 = 0,當前狀況是符合的,因此咱們須要存入該三元組,存入後,藍色指針向後移動一步,橙色指針向前移動一步,咱們發現仍爲 0 -1 + 1 = 0 仍然符合,可是若是繼續存入該三元組的話則不符合題意,因此咱們須要去重。這裏能夠藉助HashSet可是效率太差,不推薦。這裏咱們可使用 while 循環將藍色指針移動到不和剛纔相同的位置,也就是直接移動到元素 0 上,橙色指針一樣也是。則是下面這種狀況,這樣咱們就實現了去重,而後繼續判斷當前三數之和是否爲 0 。

三數之和例子

動圖解析:

三數之和

題目代碼:

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> arr = new ArrayList<List<Integer>>();
        if(nums.length < 3){
            return arr;
        }
        //排序
        Arrays.sort(nums);
        if(nums[0] > 0){
            return arr;
        }
        for(int i = 0; i < nums.length-2; i++){
            int target = 0 - nums[i];
            //去重
            if(i > 0 && nums[i] == nums[i-1]){
                continue;
            }
            int l = i+1;
            int r = nums.length - 1;
            while(l < r){
                if(nums[l] + nums[r] == target){
                    //存入符合要求的值
                    arr.add(new ArrayList<>(Arrays.asList(nums[i], nums[l], nums[r])));
                    //這裏須要注意順序
                    while(l < r && nums[l] == nums[l+1]) l++; 
                    while(l < r && nums[r] == nums[r-1]) r--;            
                    l++;
                    r--;                   
                }
                else if(nums[l] + nums[r] > target){
                    r--;
                }
                else{
                    l++;
                }
            }
        }
        return arr;
    }
}

四數之和

題目描述

給定一個包含 n 個整數的數組 nums 和一個目標值 target,判斷 nums 中是否存在四個元素 a,b,c 和 d ,使得 a + b + c + d 的值與 target 相等?找出全部知足條件且不重複的四元組。

注意:

答案中不能夠包含重複的四元組。

示例:

給定數組 nums = [1, 0, -1, 0, -2, 2],和 target = 0。

知足要求的四元組集合爲:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]

咱們已經完成了兩數之和和三數之和,這個題目應該就手到擒來了,由於咱們已經知道這類題目的解題框架,兩數之和呢,咱們就先固定第一個數 ,而後移動指針去找第二個符合的,三數之和,固定一個數,雙指針去找符合狀況的其餘兩位數,那麼咱們四數之和,也能夠先固定兩個數,而後利用雙指針去找另外兩位數。因此咱們來搞定他吧。

多指針:

解析:

三數之和是,咱們首先肯定一個數,而後利用雙指針去找另外的兩個數,咱們在這個題目裏面的解題思路是須要首先肯定兩個數而後利用雙指針去找另外兩個數,和三數之和思路基本一致很容易理解。咱們具體思路能夠參考下圖。

這裏須要注意的是,咱們的 target 再也不和三數之和同樣爲 0 ,target 是不固定的,因此解題思路不能夠徹底照搬上面的題目。另外這裏也須要考慮去重的狀況,思路和上題一致。

四數之和起始

上圖則爲咱們查找到一個符合條件的四元組的狀況,查找成功以後,下一步移動藍色指針,從新定義綠藍指針,繼續執行上面步驟。

四數之和例子

動圖解析:

四數之和

題目代碼:

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
           if(nums.length < 4){
               return new ArrayList<>(); 
           }
           Arrays.sort(nums);
           List<List<Integer>> arr = new ArrayList<>();
           for(int i = 0; i < nums.length-3; ++i){
               if(i > 0 && nums[i] == nums[i-1]){
                   continue;
               }
               for(int j = i+1; j < nums.length-2; j++){

                   if(j > i+1 && nums[j] == nums[j-1]){
                       continue;
                   }
                   int l = j+1;
                   int r = nums.length-1;
                   while(l < r){
                       int sum = nums[i] + nums[j] + nums[l] + nums[r];
                       if(sum == target){
                           //存入
                           arr.add(new ArrayList<>
                           (Arrays.asList(nums[i], nums[j], nums[l], nums[r])));
                           //去重
                           while(l < r && nums[l] == nums[l+1]){
                               l++;
                           }
                           while(l < r && nums[r] == nums[r-1]){
                               r--;
                           }
                           l++;
                           r--;
                       }
                       else if(sum > target){
                             r--;
                       }
                       else{
                             l++;
                       }
                   }
               }
           }
           return arr;
    }
}

 

經過上面的三個例子,你們是否是把此類求和問題摸的透透的啦,若是能感受到這個文章寫的很用心的話,能給您帶來一丟丟幫助的話,能麻煩您給這個文章點個贊嗎?這樣我就巨有動力寫下去啦。

另外你們若是須要其餘精選算法題的動圖解析,你們能夠微信關注下袁廚的算法小屋,我是袁廚一個酷愛作飯因此本身考取了廚師證的菜雞程序員,會一直用心寫下去的,感謝支持!

qrcode_for_gh_1f36d2ef6df9_258

相關文章
相關標籤/搜索