LeetCode两数之和o(n)算法(java语言)

       问题描述给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。

         示例给定nums={2,7,11,15},target=9。因为nums[0]=2,nums[1]=7,2+7=9,所以返回[0,1]。

-------------------------------------------------------------------------------------------------------------------------

       最笨的办法:暴力求解,先确定一个值,再从剩下的数中找到第二个值。保存第一个值用一层循环,找第二个值再用一层循环,这样内外两层循环,复杂度是o(n^2),不可取。

       既然先只确定一个值不可取,那我们应想到,确定一个值的时候,再保存下来这个值的索引。这样在一遍循环中,当找到两个符合条件的数就可以直接输出他们的索引。数组具有两个性质:数组下标和他所保存的值。我们应该利用这点,用数组,既保存这个数,又保存它的索引。 一遍循环就可以找出这两个数。

        首先进行一些预处理,将数组中不可能取到的数去掉,既找出这两个数的取值区间:

                int max = Integer.MIN_VALUE;
		int min = Integer.MAX_VALUE;

		for (int i = 0; i < nums.length; i++) {
			if (nums[i] > max)
				max = nums[i];
			if (nums[i] < min)
				min = nums[i];
		}

		int maxS = target - min;
		int minS = target - max;

		maxS = (maxS < max ? maxS : max);
		minS = (minS > min ? minS : min);

        找到数组的最大值max和最小值min,target-min决定这两个数最大可以取到多少,target-max决定这两个数最小可以取多少。最后,取max和maxS的较小值、min和minS的较大值,即为符合条件的两个数在这个数组中的取值区间。

        得到区间之后,创建一个数组,长度就是区间长度,因为区间中每个数都可能取到。数组的下标用来储存区间中的数,数组的值用来储存这个数的索引。

                int a[] = new int[maxS - minS + 1];
		for (int i = 0; i < a.length; i++)
			a[i] = -1;
        循环时,将数组中符合区间的数都插到数组中,数的值为数组下标,数在数组中的位置为数组的值,当判断到两个符合条件的数时返回。
                for (int i = 0; i < nums.length; i++) {
			if (nums[i] >= minS && nums[i] <= maxS) {
				if (a[target - nums[i] - minS] != -1)
					return new int[] { a[target - nums[i] - minS], i };
				else
					a[nums[i] - minS] = i;
			}
		}
        这里给数组赋值的时候,下标都减去了minS只是为了数组不越界,看的时候可以将minS忽略,它不具有实际意义。先确定一个数nums[i],那么便确定了与他对应的target-nums[i],判断a[target - nums[i]]的值是否为-1,如果是-1表示与nums[i]对应的这个数不在数组中,那么在数组中储存好nums[i]的位置和值。如果不是-1,表示与这两个数都在数组中,返回他们在数组中的位置即可。

猜你喜欢

转载自blog.csdn.net/q_m_x_d_d_/article/details/80198801
今日推荐