LeetCode題解1-兩數之和(Java)

題目描述:

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

你可以假設每種輸入只會對應一個答案。但是,你不能重復利用這個數組中同樣的元素。

示例:

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

因為 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/two-sum
著作權歸領扣網絡所有。商業轉載請聯系官方授權,非商業轉載請注明出處。

題目分析:

題目中有以下條件是我們正確解答題目的關鍵:

  1. “假設每種輸入只會對應一個答案”,說明數組中如果有重復數字并且重復數字是答案的一部分,那么重復數字有且僅有兩個并且這兩個就是答案,如:
給定 nums = [3, 3, 1, 9], target = 6
因為 nums[0] + nums[1] = 3 + 3 = 6
所以返回 [0, 1]
  1. “不能重復利用這個數組中同樣的元素”,無法使用雙層循環這樣的暴力解法。

解答:
為了便于說明我們還是先使用暴力解法:
使用雙層循環,第一層循環找到當前值與目標值的差值tempJ。第二層循環尋找tempJ是否存在,如果存在則返回其位置

public int[] twoSum(int[] nums, int target) {
        int i = 0, j = 0;
        for (; i < nums.length; i++) {
            int tempJ = target - nums[i];
            j = getNumJ(nums,tempJ,i);
            if(j != -1 ){
                break;
            }
        }
        return new int[]{i, j};
    }

    /**
     * @param nums
     * @param tempJ
     * @param i
     * @return 如何元素存在則返回元素的位置,否則返回-1
     */
    private int getNumJ(int[] nums, int tempJ ,int i) {
        for (int j = i+1; j < nums.length; j++) {
            if(nums[j] == tempJ){
                return j;
            }
        }
        return -1;
    }

我們可以看到在上述解法的時候,找tempJ的時候元素被使用了多次,我們應當尋找快速定位到tempJ的方式;我們可以想到利用HashMap來存儲數據,從而快速定位。
最終我們得到的解決方案如下:

public class Solution {

    public int[] twoSum(int[] nums, int target) {
        HashMap<Integer,Integer> numMap = new HashMap<>();
        int i = 0, j = 0;
        for (; i < nums.length; i++) {
            int tempJ = target - nums[i];
            Integer position = numMap.get(tempJ);
            if(position != null){
                j = position;
                break;
            }
            numMap.put(nums[i],i);
        }
        return new int[]{j, i};
    }
}

那么HashMap在get數據難道不是通過遍歷的方式么?當然不是,HashMap是Java中較為基礎的數據接構,感興趣的同學可以去閱讀下源碼。這里簡單的說明下他是如何通過hash存儲和取值的。
在jdk1.8之前hashmap是使用數組+鏈表的形式存儲的,數據結構如下圖


HashMap數據結構.png

當我們向該數據結構中存鍵值對(key-value)時,會獲取“key”的hashCode(不同類型key的hashCode的生成方式可以參看該類的hashCode方法,如Integer的hashCode為Integer的value),獲取到的每一個hashCode對應數組上的一個位置,插入的時候直接將value放到該位置上,如果當前位置不為空,則直接放到該位置對應的鏈表中。至于取值的方式就顯而易見了,直接獲取key的hashCode,找到它在數組中的位置,獲取該位置的值即可,如果當前位置的key不是我們想要的那個key,則需要遍歷該位置對應的鏈表獲取到對應的值。到這里你可能會說,這里還是會遍歷,是否能滿足只遍歷一次數據的需求?當然能,理由在“題目分析”的第一點已經說了,我們需要的答案的數據最多只有兩個重復的,并且我們在找j的時候,j還沒有被插入,因此不會存在hash沖突,不需要遍歷。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容