Input array is sorted三種解法對比
阿新 • • 發佈:2018-12-14
本文對比LeetCode 167. Two Sum II - Input array is sorted三種不同的解法並進行優化,拋磚引玉,望各位大佬指教。
題目:
Given an array of integers that is already sorted in ascending order, find two numbers such that they add up to a specific target number.
The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2.
Note:
- Your returned answers (both index1 and index2) are not zero-based.
- You may assume that each input would have exactly one solution and you may not use the same element twice.
Example:
Input: numbers = [2,7,11,15], target = 9 Output: [1,2] Explanation: The sum of 2 and 7 is 9. Therefore index1 = 1, index2 = 2.
第一種解法:暴力解法,雙重迴圈。
class Solution { //雙重迴圈 public int[] twoSum(int[] numbers, int target) { int[] res = new int[2]; for(int i=0;i<numbers.length;i++){ for(int j=0;j<numbers.length;j++) if(numbers[i]+numbers[j]==target && i!=j){ if(numbers[i]<numbers[j]){ res[0]=i+1; res[1]=j+1; }else{ res[0]=j+1; res[1]=i+1; } } } return res; } }
雙重迴圈這種暴力解法時間複雜度O(n^2),顯然不是一個好的方法,在這道題裡面提交的時候會顯示超時,pass!
第二種解法:既然陣列已經有序,那你是否想到了利用二分查詢。在陣列中二分查詢目標元素最簡單的程式碼如下,需要注意其中的邊界問題。
public int binarySearch(int[] arr, int target) {
int n = arr.length;
int l = 0, r = n - 1; //在[l,r]範圍內尋找target
while (l <= r) { //當l==r時,區間[l,r]依然是有效的
int mid = (l + r) / 2;
if (arr[mid] == target) {
return mid;
}
if (target > arr[mid]) {
l = mid + 1; //target在[mid+1,r]中
} else {
r = mid - 1;
}
}
return -1;
}
本題中先選擇一個元素x,然後利用二分查詢在剩下的元素中查詢(target-x),找到的話返回索引。
class Solution {
//二分搜尋
public int[] twoSum(int[] numbers, int target) {
for(int i=0;i<numbers.length;i++){
int index = binarySearch(numbers,i+1,target-numbers[i]);
if(index !=-1){
System.out.println(index);
int[] res = new int[]{i+1,index+1};
return res;
}
}
return new int[2];
}
public int binarySearch(int[] arr, int l, int target){
int n = arr.length;
int r=n-1;
while(l<=r){
int mid = (l+r)/2;
if(arr[mid]==target){
return mid;
}
if(target > arr[mid]){
l = mid + 1;
}else{
r = mid -1;
}
}
return -1;
}
}
這種解法的時間複雜度提高到O(nlogn),貌似還可以。
第三種解法:到此,應該問自己,是否還可以繼續優化呢?答案是肯定的。當然還可以利用經典的指標對撞的方法解決。指標對撞,即分別定義一個頭指標和尾指標,分別陣列的頭和尾向中間移動去對撞,問題在對撞的過程中迎刃而解。指標對撞問題的詳細分析在後面再總結分享。
class Solution {
//指標碰撞
public int[] twoSum(int[] numbers, int target) {
int n=numbers.length;
int i=0,j=n-1;
while(numbers[i]+numbers[j] != target){
if(numbers[i]+numbers[j] > target){
j--;
}else{
i++;
}
}
int[] res = new int[]{i+1,j+1};
return res;
}
}
指標碰撞解法的時間複雜度為O(n),我認為已經算是一種不錯的解法,到此先告一段落。