leetcode上面第一题two sum算法求解

xigua1102 2017-09-08 11:40:18
leetcode上面的第一题,two sum
简单来说,就是给一个整数数组,和一个目标数,然后在数组里找出两个数的和为目标数,输出这两个数的下标
比如数组 [2, 7, 11, 15], 目标 9
2+7=9,输出0,1
题目很简单,比较的是算法执行时间,我自己写的是常规算法,不入流
然后看了一下,别人3ms的答案,但是看不懂,请教一下大家


class Solution {
public int[] twoSum(int[] nums, int target) {

int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for (int num : nums) {
if (num < min) {
min = num;
}
if (num > max) {
max = num;
}
}
int validMin = Math.max(min, target - max);
int validMax = Math.min(max, target - min);

int length = validMax - validMin + 1;
int[] array = new int[length];
int offset = validMin;
Arrays.fill(array, -1);

for(int i = 0 ; i != nums.length ; ++i) {
int num = nums[i];
if (num >= validMin && num <= validMax) {
int firstIndex = array[num - offset];
if (firstIndex == -1) {
int diff = target - num;
array[diff - offset] = i;
} else {
return new int[]{firstIndex, i};
}
}
}

throw null;
}
}

像其他7ms,8ms的算法都能理解,就这个算法完全不懂。
我想知道,这个算法使用的原理叫什么,为什么这么处理一下,就可以达到目的
请知道的大侠赐教,谢谢
...全文
425 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
z止于至善 2018-07-07
  • 打赏
  • 举报
回复
//暴力法
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] result = new int[2];
for(int i=0; i<nums.length; i++){
for(int j=nums.length-1; j>i; j--){
if(nums[i]+nums[j]==target){
result[0]=i;
result[1]=j;
break;
}
}
}
return result;
}
}
xigua1102 2017-09-11
  • 打赏
  • 举报
回复
还有一个答案,显示的是4ms的答案,一样不好理解

public class Solution {
    public int[] twoSum(int[] nums, int target) {
        int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        int[] out = new int[2];
        for (int i : nums) {
            if (i > max) max = i;
            if (i < min) min = i;
        }
        int length = max - min + 1;
        int[] array = new int[length];
        for (int i : nums) {
            array[i - min]++;
        }
        target = target - 2 * min;
        for (int i = 0; i <= target; i++) {
            
            if (target - i >= length) continue;
            if (array[i]-- > 0 && array[target - i]-- > 0) {
                for (int j = 0; j <  nums.length; j++) {
                    if (nums[j] == i + min) {
                        nums[j] = target -i + min - 1;
                        out[0] = j;
                        break;
                    }
                }
                for (int j = 0; j <  nums.length; j++) {
                    if (nums[j] ==target -  i + min) {
                        out[1] = j;
                        break;
                    }
                }
                break;
            }
        }
        return out;
    }
}
看得脑袋痛。。。不知道别人怎么想出这个算法来的。。。
xigua1102 2017-09-11
  • 打赏
  • 举报
回复
我可能有点理解这个算法了 就是先筛选整个数组,把过大的和过小的取消,两个数的和在target范围内的留下 然后创建一个有效范围数值长度内的数组,记录下标 脑子不够用啊。。。。
xigua1102 2017-09-11
  • 打赏
  • 举报
回复
引用 2 楼 soton_dolphin 的回复:
最关键的就是这两句: int firstIndex = array[num - offset]; 看看第一个加数有没有存在 diff = target - num array[diff - offset] = i; 如果第一个加数不存在,就把第一个加数存到数组里 直到 遇到一个num = diff, 或者抛出null 表示没有两个数可以相加得到target
非常感谢您的回复。 我主要想问的是,这种算法是怎么得出来的,或者说这种算法在数学上或者计算机理论上有没有什么专业术语来描述。 比如说,一看到题目,最简单的一个算法,很容易想到 就是数组的数和后面的相加,等于target的就是答案 然后进一步需要减少运行时间

public int[] twoSum(int[] nums, int target) {
	        int[] res = new int[2];
	        
	        HashMap<Integer, Integer> map = new HashMap<>();
	        
	        for (int i = 0; i < nums.length; i++) {
	            int diff = target - nums[i];
	            if (map.containsKey(diff)) {
	                res[0] = map.get(diff);
	                res[1] = i;
	                return res;
	            }
	            map.put(nums[i], i);
	        }
	        return res;
	    }
	
从map中查找结果,map的get速度很快,最长时间也就是把整个数组过一遍,比逐个相加快了很多。 这些我都可以理解,但是,3ms这个答案,我实在是不知道怎么想才能想到这个办法
soton_dolphin 2017-09-08
  • 打赏
  • 举报
回复
最关键的就是这两句: int firstIndex = array[num - offset]; 看看第一个加数有没有存在 diff = target - num array[diff - offset] = i; 如果第一个加数不存在,就把第一个加数存到数组里 直到 遇到一个num = diff, 或者抛出null 表示没有两个数可以相加得到target
soton_dolphin 2017-09-08
  • 打赏
  • 举报
回复

class Solution {
    public int[] twoSum(int[] nums, int target) {

        // 初始化最小的数是 int 最大值,这样就能确定数组里每个数都小于min
        int min = Integer.MAX_VALUE;

        // 初始化最大的数是 int 最小值,这样就能确定数组里每个数都大于max
        int max = Integer.MIN_VALUE;

        for (int num : nums) {
            //找到数组里最大的数
            if (num < min) {
                min = num;
            }

            //找到数组里最小的数
            if (num > max) {
                max = num;
            }
        }

        // 找到数组里组成target 数值的下限
        int validMin = Math.max(min, target - max);

        // 找到数组里组成 target 数值的上限
        int validMax = Math.min(max, target - min);

        // 计算上限和下限之间的差值
        int length = validMax - validMin + 1;

        int[] array = new int[length];
        int offset = validMin;
        Arrays.fill(array, -1);

        // 遍历原始的数组
        // 寻找 num = diff
        for(int i = 0 ; i != nums.length ; ++i) {
            int num = nums[i];
            // 过滤走原始数组里不符合上限和下限的元素
            if (num >= validMin && num <= validMax) {
                // 检查 num - offset 得结果是不是第一次出现在数组里
                // 如果是第一次出现,数组对应的数值就是 - 1
                int firstIndex = array[num - offset];
                // 如果是第一次出现
                if (firstIndex == -1) {
                    // 计算目标和目前数字的差
                    int diff = target - num;
                    // 用另一个加数的值减去offset作为数组的下标,并保存另一个加数在原始数组里的下标
                    array[diff - offset] = i;
                } else {
                    // 如果num - offset 出现过,也就是加数的另一个数已经在原始数组里遍历过了
                    // 那就返回储存的值和现在这个数在原始数组里的下标值
                    return new int[]{firstIndex, i};
                }
            }
        }

        throw null;
    }

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧