leetcode 两数之和--比哈希快的方法
题目原题
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
哈希解法 3ms
一般网路上看的哈希解法是,也是相当快了
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (map.containsKey(complement)) {
return new int[] { map.get(complement), i };
}
map.put(nums[i], i);
}
return null;
}
目前leetcode 1ms解法
但leetcode神奇之处就是会不断追求极致,目前Java 1ms上的范例是
public int[] twoSum(int[] nums, int target) {
int indexMax = 0xfff;
int[] array = new int[indexMax + 1];
for (int i = 0; i < nums.length; i++) {
int diff = (target - nums[i]) & indexMax;
if (array[diff] != 0) {
return new int[]{array[diff] - 1,i};
}
array[nums[i] & indexMax] = i+1;
}
return null;
}
}
看到了神奇数字 0xfff,这时就估计是根据测试范例做的硬编码。
把测试数据改为
int[] nums= new int [100000];
for (int i = 0;i<100000;i++){
nums[i]=i;
}
System.out.println(Arrays.toString(twoSum(nums, 99999)));
跑出来的答案是错误的[847, 848]
优化 1ms解法
在百思不得其解后,刷了微信小程序 算法面试 看到有更优解
public int[] twoSum(int[] nums, int target) {
final int i1 =nums.length;
int il2 =(i1 >> 2) -1;
int pot =2 ;
while((il2 >>=1) > 0 ){
pot <<= 1;
}
final int bitMod =pot -1;
final int[] bucket =new int[pot];
final int[] linked =new int[i1];
final int firstVal = nums[0];
for (int i=1 ; i<i1 ;i++){
int currNum = nums[i];
int complement = target -currNum;
if (complement == firstVal){
return new int[] {0 ,i};
}
int complementLLIndex = bucket[complement & bitMod];
while(complementLLIndex != 0){
if(nums[complementLLIndex] == complement){
//Found
return new int[] {complementLLIndex,i};
}
complementLLIndex =linked[complementLLIndex];
}
int currNumLLIndex = currNum & bitMod;
linked[i] = bucket[currNumLLIndex];
bucket[currNumLLIndex] = i;
}
return null;
}
答案则是[49999, 50000] , 不过比较复杂 , 在这抛砖引玉,希望大神能做优化~