一、前言
盲目刷题只会让自己心态爆炸,所以本期14天算法学习计划,也是LeetCode上的 *[算法]*学习计划,在本专栏的每一篇文章都会整理每一天的题目并给出详细题解,以及知识点的整理
二、知识点
戳下方链接查看⬇⬇⬇
14天刷爆LeetCode算法学习计划——Day02双指针(1)
三、LeetCode167. 两数之和 II - 输入有序数组
1.题目
LeetCode167. 两数之和 II -输入有序数组
给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列 ,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是numbers[index1] 和 numbers[index2] ,则 1 <= index1 < index2 <= numbers.length 。
以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1 和 index2。
你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。
你所设计的解决方案必须只使用常量级的额外空间。
示例 1:
输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此index1 = 1, index2 = 2 。返回 [1, 2] 。
示例 2:
输入:numbers = [2,3,4], target = 6
输出:[1,3]
解释:2 与 4 之和等于目标数 6 。因此index1 = 1, index2 = 3 。返回 [1, 3] 。
示例 3:
输入:numbers = [-1,0], target = -1
输出:[1,2]
解释:-1 与 0 之和等于目标数 -1 。因此index1 = 1, index2 = 2 。返回 [1, 2] 。
2.解题思路(含图)
- 我们可以定义左右指针,并将左右指针指向的值的和赋值给一个变量sum
- 当我们的 sum 比 targer(要求的和)小 的话,由于数组按照递增的顺序,既然此时right指向的已经是数组最大值了,那么只能将left指向的值变得更大,即 left的值加1
- 当我们的sum 比 target(要求的和)大的话,由于数组按照递增的顺序,既然此时left指向的已经是数组最小值了,那么只能将right指向的值变得更小,即 right的值减1
- 重复操作,直至 sum = target
3.注意事项
- 数组的下标值是从1开始记录的,所以在输出时 left 和 right 的值要加1
- 由于此时要输出的是数组形式,所以返回值不能是一个值,而要是数组,即 return new int[] {left + 1,right + 1}
4.代码实现
class Solution { public int[] twoSum(int[] numbers, int target) { //定义左指针 int left = 0; //定义右指针 int right = numbers.length - 1; //求下标值 while(left < right){ //用变量sum接收左右指针指向元素的和,使代码更简洁 int sum = numbers[left] + numbers[right]; //指针指向元素的和比目标数大 if(sum > target){ right--; } //指针指向元素的和比目标数小 else if(sum < target){ left++; } //指针指向元素的和比目标数相等 else{ //以数组形式返回下标值 return new int[] {left+1,right+1}; } } //如果找不到,就返回元素都是-1的数组 return new int[] {-1,-1}; } }
5.验证代码
6.时间复杂度和空间复杂度
- 时间复杂度:O(n)
- 空间复杂度:O(1)
7.其它解法
1️⃣二分查找
class Solution { public int[] twoSum(int[] numbers, int target) { for (int i = 0; i < numbers.length; ++i) { int low = i + 1, high = numbers.length - 1; while (low <= high) { int mid = (high - low) / 2 + low; if (numbers[mid] == target - numbers[i]) { return new int[]{i + 1, mid + 1}; } else if (numbers[mid] > target - numbers[i]) { high = mid - 1; } else { low = mid + 1; } } } return new int[]{-1, -1}; } }
- 时间复杂度:O(nlogn)
- 空间复杂度:O(1)
2️⃣暴力求解(我的第一次尝试)
class Solution { public int[] twoSum(int[] numbers, int target) { int[] result = new int[2]; for(int index1 =0; index1 <= numbers.length- 1; index1++){ for(int index2 = index1+1; index2 <= numbers.length - 1; index2++){ if(numbers[index1] + numbers[index2] == target){ result[0] = index1 + 1; result[1] = index2 + 1; } } } return result; } }
四、结语
本题的暴力解法应该是大家的第一想法,但是如何优化代码,并降低时间复杂度就需要用到算法了,本题一定要明白双指针的含义才能在下次看到题目时不会再只用暴力求解的方式去解决问题了