阅读更多
1 tips
1.1 左右边界的递归
循环条件是while(left < right)
,递增必然是left = mid +1
与right = mid
,这是定死的,否则对于left = right -1
时,left < right
将会永远成立
1.2 返回值的讨论
循环条件是left < right
,因此循环结束时left == right
,只需要讨论以下三种情况即可
nums[left] < target
nums[left] == target
nums[left] > target
1.3 循环位移的二分查找
共有四题,分别是33、81、153、154
对于查找给定值
这个给定值可能位于任意一段序列中
通过nums[mid]与nums[right]的大小关系来确定mid位于第一段还是第二段序列中,再根据target的值来进行left和right的更新
查找最值(最大或最小)
这个最值必定位于某一段序列中,因此必须保证[left,right],要么包含两段序列,要么位于那段存在最值的序列
对于153和154而言(最小值),当nums[mid] < nums[right]
时,只能right = mid
,而不能right = mid - 1
。因为如果执行right = mid - 1
,可能会使得[left,right]只包含第一段序列,这样的话找到的是第一段的最小值,而非整个的最小值
2 Question-4[★★★★]
Median of Two Sorted Arrays
There are two sorted arrays nums1 and nums2 of size m and n respectively.
Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n))
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class Solution { public double findMedianSortedArrays (int [] nums1, int [] nums2) { int len = nums1.length + nums2.length; return (helper(nums1, 0 , nums2, 0 , (len + 1 ) / 2 ) + helper(nums1, 0 , nums2, 0 , (len + 2 ) / 2 )) / 2 ; } private double helper (int [] nums1, int pos1, int [] nums2, int pos2, int index) { if (pos1 == nums1.length) return nums2[pos2 + index - 1 ]; else if (pos2 == nums2.length) return nums1[pos1 + index - 1 ]; else if (index == 1 ) return nums1[pos1] < nums2[pos2] ? nums1[pos1] : nums2[pos2]; int stepForward = index / 2 ; int nextPos1 = pos1 + stepForward - 1 ; int nextPos2 = pos2 + stepForward - 1 ; int val1 = nextPos1 < nums1.length ? nums1[nextPos1] : Integer.MAX_VALUE; int val2 = nextPos2 < nums2.length ? nums2[nextPos2] : Integer.MAX_VALUE; if (val1 < val2) return helper(nums1, nextPos1 + 1 , nums2, pos2, index - stepForward); else return helper(nums1, pos1, nums2, nextPos2 + 1 , index - stepForward); } }
还有一个非常简单的思路,与合并两个有序数组是一样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 class Solution { public double findMedianSortedArrays (int [] nums1, int [] nums2) { int totalLength = nums1.length + nums2.length; int mid1Index = totalLength - 1 >> 1 ; int mid2Index = totalLength >> 1 ; int iter1 = 0 , iter2 = 0 ; int cnt = 0 ; int curVal; int mid1 = 0 , mid2 = 0 ; while (iter1 < nums1.length && iter2 < nums2.length) { if (nums1[iter1] <= nums2[iter2]) { curVal = nums1[iter1++]; } else { curVal = nums2[iter2++]; } if (cnt == mid1Index) { mid1 = curVal; } if (cnt == mid2Index) { mid2 = curVal; } cnt++; } while (iter1 < nums1.length) { curVal = nums1[iter1++]; if (cnt == mid1Index) { mid1 = curVal; } if (cnt == mid2Index) { mid2 = curVal; } cnt++; } while (iter2 < nums2.length) { curVal = nums2[iter2++]; if (cnt == mid1Index) { mid1 = curVal; } if (cnt == mid2Index) { mid2 = curVal; } cnt++; } return 1.0d * (mid1 + mid2) / 2 ; } }
3 Question-33[★★★★★]
Search in Rotated Sorted Array
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
分类讨论条件
由于循环条件是left < right
,当right = left + 1
时,left == mid
,而mid < right
一定成立,为了避免讨论特殊情况,可以用nums[mid]
与nums[right]
的大小关系作为分类条件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 class Solution {public : int search (std::vector<int >& nums, int target) { int left = 0 ; int right = nums.size () - 1 ; while (left < right) { int mid = left + ((right - left) >> 1 ); if (nums[mid] == target) { return mid; } if (nums[mid] == nums[left]) { left++; } else if (nums[mid] > nums[left]) { if (nums[left] <= target && target <= nums[mid]) { right = mid; } else { left = mid + 1 ; } } else { if (nums[mid] <= target && target <= nums[right]) { left = mid + 1 ; } else { right = mid; } } } if (nums[left] == target) { return left; } return -1 ; } };
4 Question-34[★★★]
Search for a Range
Given an array of integers sorted in ascending order, find the starting and ending position of a given target value.
Your algorithm’s runtime complexity must be in the order of O(log n)
.
If the target is not found in the array, return [-1, -1]
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 public class Solution { public int [] searchRange(int [] nums, int target) { return new int []{leftBoundary(nums, target), rightBoundary(nums, target)}; } private int leftBoundary (int [] nums, int target) { if (nums == null || nums.length == 0 ) return -1 ; int left = 0 , right = nums.length - 1 ; if (nums[left] > target || nums[right] < target) return -1 ; while (left < right) { int mid = left + (right - left >> 1 ); if (nums[mid] >= target) { right = mid; } else { left = mid + 1 ; } } return nums[left] == target ? left : -1 ; } private int rightBoundary (int [] nums, int target) { if (nums == null || nums.length == 0 ) return -1 ; int left = 0 , right = nums.length - 1 ; if (nums[left] > target || nums[right] < target) return -1 ; while (left < right) { int mid = left + (right - left >> 1 ); if (nums[mid] <= target) { left = mid + 1 ; } else { right = mid; } } return nums[left] == target ? left : left - 1 >= 0 && nums[left - 1 ] == target ? left - 1 : -1 ; } }
5 Question-35[★★★]
Search Insert Position
Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class Solution { public int searchInsert (int [] nums, int target) { if (nums.length == 0 ) return 0 ; if (target < nums[0 ]) return 0 ; if (target > nums[nums.length - 1 ]) return nums.length; int left = 0 , right = nums.length - 1 ; while (left < right) { int mid = left + (right - left >> 1 ); if (nums[mid] == target) return mid; else if (nums[mid] < target) { left = mid + 1 ; } else { right = mid; } } return left; } }
6 Question-50[★★]
Pow(x, n)
Implement pow(x, n)
.
1 2 3 4 5 6 7 8 9 10 11 12 public class Solution { public double myPow (double x, int n) { if (n == 0 ) return 1 ; else if (n == 1 ) return x; else if (n == -1 ) return 1 / x; int half = n / 2 ; double temp = myPow(x, half); return temp * temp * myPow(x, n - half * 2 ); } }
7 Question-74[★★★★★]
Search a 2D Matrix
Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:
Integers in each row are sorted from left to right.
The first integer of each row is greater than the last integer of the previous row.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public class Solution { public boolean searchMatrix (int [][] matrix, int target) { if (matrix.length == 0 || matrix[0 ].length == 0 ) return false ; int top = 0 , bottom = matrix.length - 1 ; if (target < matrix[0 ][0 ]) return false ; while (top < bottom) { int mid = top + (bottom - top >> 1 ); if (matrix[mid][0 ] == target) return true ; else if (matrix[mid][0 ] < target) { top = mid + 1 ; } else { bottom = mid; } } int row = matrix[top][0 ] > target ? top - 1 : top; int left = 0 , right = matrix[row].length - 1 ; while (left < right) { int mid = left + (right - left >> 1 ); if (matrix[row][mid] == target) return true ; else if (matrix[row][mid] < target) { left = mid + 1 ; } else { right = mid; } } return matrix[row][left] == target; } }
以下这种方法的思路是,先往上升row,然后再减col。不可能出现先递减col再递增row然后找到target的情况,因为递减col说明target < matrix[row][col]
,那么matrix[row][col] < matrix[row+1][?]
,因此target < matrix[row+1][?]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class Solution { public boolean searchMatrix (int [][] matrix, int target) { if (matrix.length == 0 || matrix[0 ].length == 0 ) return false ; int m = matrix.length, n = matrix[0 ].length; if (target < matrix[0 ][0 ] || target > matrix[m - 1 ][n - 1 ]) return false ; int row = 0 , col = n - 1 ; while (row < m && col >= 0 ) { if (target == matrix[row][col]) return true ; else if (target > matrix[row][col]) { row++; } else { col--; } } return false ; } }
8 Question-81[★★★★★]
Search in Rotated Sorted Array II
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
思路:通过nums[mid]
与nums[right]
的关系来判断mid位于那一段有序的序列上。如果nums[mid]>nums[right]
,那么意味着[left,right]
必然存在两段序列且mid位于左边这段序列上,而nums[mid]<nums[right]
意味着可能[left,right]
本身就是有序的,或者存在两端序列且mid位于右边这段
分类讨论条件
由于循环条件是left < right
,当right = left + 1
时,left == mid
,而mid < right
一定成立,为了避免讨论特殊情况,可以用nums[mid]
与nums[right]
的大小关系作为分类条件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class Solution { public boolean search (int [] nums, int target) { if (nums == null || nums.length == 0 ) return false ; int left = 0 , right = nums.length - 1 ; while (left < right) { int mid = left + (right - left >> 1 ); if (nums[mid] == target) { return true ; } else if (nums[mid] < nums[right]) { if (nums[mid] < target && target <= nums[right]) { left = mid + 1 ; } else { right = mid; } } else if (nums[mid] > nums[right]) { if (nums[left] <= target && target < nums[mid]) { right = mid; } else { left = mid + 1 ; } } else { right--; } } return nums[left] == target; } }
9 Question-153[★★★★★]
Find Minimum in Rotated Sorted Array
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
Find the minimum element.
You may assume no duplicate exists in the array.
分类讨论条件
由于循环条件是left < right
,当right = left + 1
时,left == mid
,而mid < right
一定成立,为了避免讨论特殊情况,可以用nums[mid]
与nums[right]
的大小关系作为分类条件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution { public int findMin (int [] nums) { int left = 0 , right = nums.length - 1 ; while (left < right) { int mid = left + (right - left >> 1 ); if (nums[mid] < nums[right]) { right = mid; } else { left = mid + 1 ; } } return nums[left]; } }
10 Question-154[★★★★★]
Find Minimum in Rotated Sorted Array II
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
Find the minimum element.
The array may contain duplicates.
这题思路与153一样,只是在nums[mid]与nums[right]相等时特殊处理一下,因为此时并不知道mid位于哪一段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution { public int findMin (int [] nums) { int left = 0 ; int right = nums.length - 1 ; while (left < right) { int mid = left + (right - left >> 1 ); if (nums[mid] < nums[right]) { right = mid; } else if (nums[mid] > nums[right]) { left = mid + 1 ; } else { right--; } } return nums[left]; } }
11 Find Peak Element
A peak element is an element that is strictly greater than its neighbors.
Given an integer array nums, find a peak element, and return its index. If the array contains multiple peaks, return the index to any of the peaks.
You may imagine that nums[-1] = nums[n] = -∞.
You must write an algorithm that runs in O(log n) time.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class Solution { public int findPeakElement (int [] nums) { int left = 0 , right = nums.length - 1 ; while (left < right) { int mid = left + (right - left >> 1 ); if (nums[mid] < nums[mid + 1 ]) { left = mid + 1 ; } else if (nums[mid] > nums[mid + 1 ]) { right = mid; } else { boolean canFind = false ; for (mid = left; mid + 1 <= right; mid++) { if (nums[mid] < nums[mid + 1 ]) { canFind = true ; left = mid + 1 ; break ; } else if (nums[mid] > nums[mid + 1 ]) { canFind = true ; right = mid; break ; } } if (!canFind) { return -1 ; } } } return left; } }
12 Question-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. Please note that 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class Solution { public int [] twoSum(int [] nums, int target) { for (int i = 0 ; i < nums.length - 1 ; i++) { int j = findTarget(nums, i + 1 , target - nums[i]); if (j != -1 ) { return new int []{i + 1 , j + 1 }; } } return null ; } private int findTarget (int [] nums, int left, int target) { int right = nums.length - 1 ; while (left < right) { int mid = left + (right - left >> 1 ); if (nums[mid] == target) return mid; else if (nums[mid] < target) { left = mid + 1 ; } else { right = mid; } } return nums[left] == target ? left : -1 ; } }
13 Question-240[★★★]
Search a 2D Matrix II
Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:
Integers in each row are sorted in ascending from left to right.
Integers in each column are sorted in ascending from top to bottom.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class Solution { public boolean searchMatrix (int [][] matrix, int target) { if (matrix.length == 0 ) return false ; int m = matrix.length; if (matrix[0 ].length == 0 ) return false ; int n = matrix[0 ].length; if (target < matrix[0 ][0 ] || target > matrix[m - 1 ][n - 1 ]) return false ; int row = 0 , col = n - 1 ; while (row < m && col >= 0 ) { if (matrix[row][col] == target) return true ; else if (matrix[row][col] > target) { col--; } else { row++; } } return false ; } }