先從Easy開始吧,畢竟菜。
原題:
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.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
第一次提交(已經很久以前了)
public class Solution {
public int[] twoSum(int[] nums, int target) {
for(int i = 0; i<nums.length-1; i++ ){
int num1 = nums[i];
int num2 = target-num1;
for(int j = i+1; j<nums.length;j++){
if(num2==nums[j]){
return new int[]{i,j};
}
}
}
return new int[]{1,1};
}
}
用了2個for循環,窮舉了所有的可能,直到找到正確的結果。
看下runtime:
可以看出效率是比較低的。
首先遍歷數組,時間復雜度是Θ(n),每個循環里面又需要遍歷一部分的數字,時間復雜度是Θ(n),總的時間復雜度是Θ(n2)。
那么如何提升呢?首先數組是肯定要遍歷一次的,那么只能在每一步的操作上面思考了。
for(int i = 0; i < nums. length; i++)
當循環到 nums[i] 的時候,需要快速的確定是否存在與其和為target的數,如何做到使這一步的復雜度小于Θ(n)呢?看了下提示,那就是使用HashMap。
因為HashMap查找的時間復雜度是Θ(1),所以整體的時間復雜度可以降到Θ(n)!
第二次提交
public class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> exist = new HashMap();// map<數字,序號>
for(int i = 0 ; i < nums.length; i++){
if(exist.keySet().contains(nums[i])){
return new int[]{exist.get(nums[i]), i};
}
exist.put(target - nums[i], i);
}
return new int[]{0,0};
}
}
可以看到,runtime明顯提升了一大截。
最后看看最快的是怎么做的,只用了3ms:
public class Solution {
public int[] twoSum(int[] nums, int target) {
short[] map = new short[20050];//新建一個map數組做映射
int size = 50;
for (int i = 0; i < nums.length; i++) {
map[nums[i] + size] = (short) (i + 1);
int diff = target - nums[i + 1] + size;
if (diff < 0) continue;
short d = map[diff];
if (d > 0)
return new int[]{d - 1, i + 1};
}
return null;
}
}
看起來一臉懵逼,循環里面的語句一句句分析一下。
map[nums[i] + size] = (short) (i + 1);
每遍歷一個數組元素,把其序號+1保存在map[nums[i] + size] 中。(為什么保存i + 1而不保存i,是因為如果i == 0的話就不能分辨出是默認值還是有保存過了)相當于建立了 nums[i] + size -> i + 1 [1] 的映射關系(事實上,nums[i] + size很可能是負數,理論上不應該這么寫)。
int diff = target - nums[i + 1] + size;
這個diff是什么含義?target - nums[i + 1] 好理解,其和數組第i + 1項的和是target,滿足題目要求。假設這個數存在于nums數組中,且他的序號為k,即:
nums[k] == target - nums[i + 1],
那么:
diff == nums[k] + size,
眼熟啊!從[1]式中可以看出,在map數組中:
nums[k] + size -> k + 1,
即是在map數組中的對應關系是
diff -> k + 1
short d = map[diff];
if (d > 0)
return new int[]{d - 1, i + 1};
這樣分析過來,這句話就好理解了:如果對于nums[i + 1]來說,和其和為target的數nums[k]已經遍歷過并保存在了map中,那么map中一定會有:
diff -> k + 1
這個對應關系,即 d == map[diff] == k + 1。我們知道java中short默認值為0,而 k + 1必然是大于0的,所以如果 d > 0,說明:
nums[i + 1] + nums[k] == target,
滿足題目條件,因為d == k + 1,所以返回:
return new int[]{d - 1, i + 1};
邏輯并不是很難,本質上和hashmap有異曲同工之妙,但是有個magic numberint size = 50;
這個根據數據集來的數,看來是針對測試集精心準備的。