前言 本部分记录,leetcode上面关于数组、二分查找等部分题目的思路,动态更新。
本题是典型的二分查找题目,题目的前提是数组为有序数组,同时题目还强调数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的,这些都是使用二分法的前提条件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Solution { public int search(int [] nums, int target) { int left = 0 , right = nums.length-1 ; while(left <= right){ int mid = left + (right - left)/2 ; int num = nums[mid]; if (num == target){ return mid; }else if (num < target){ left = mid + 1 ; }else { right = mid - 1 ; } } return -1 ; } }
复杂度分析
时间复杂度:O*(log*n),其中 n 是数组的长度。
空间复杂度:O(1)。
还是二分查找,相对于704题来说,相当于多了一个额外的条件:即如果不存在数组中的时候需要返回按顺序插入的位置。
这样问题可以转化为:在一个有序数组中找到一个大于等于target的下标
具体实现:和前面二分查找一样,但查找结束如果没有相等值则返回left,该值始终为需要插入的位置 (至于为什么可以用几个实例理解一下)
或者利用下面方法理解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution { public int searchInsert (int [] nums, int target) { int left = 0 , right = nums.length-1 ,ans = nums.length; while (left <= right){ int mid = left+((right - left)>>1 ); if (target <= nums[mid]){ ans = mid; right = mid - 1 ; }else { left = mid + 1 ; } } return ans; } }
想到一种比较好记忆的方法如下所示:
缺点在于:如果把int换成float,第四行代码的target+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 class Solution { public int [] searchRange(int [] nums, int target) { int leftIdx = searchIdx(nums,target); int rightIdx = searchIdx(nums,(target+1 ))-1 ; if (leftIdx==nums.length || nums[leftIdx]!=target ){ return new int []{-1 ,-1 }; }else { return new int []{leftIdx,rightIdx}; } } public int searchIdx (int [] nums, int target) { int left = 0 , right = nums.length - 1 , ans = nums.length; while (left <= right){ int mid = (left+right)>>1 ; if (nums[mid] >= target ){ ans = mid; right = mid-1 ; }else { left = mid +1 ; } } return ans; } }
附上官方题解,其实相比于上面解法,定义的seach方法加了一个选择条件而已。推荐记忆理解下面这个解法:
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 class Solution { public int [] searchRange(int [] nums, int target) { int leftIdx = binarySearch(nums, target, true ); int rightIdx = binarySearch(nums, target, false ) - 1 ; if (leftIdx <= rightIdx && rightIdx < nums.length && nums[leftIdx] == target && nums[rightIdx] == target) { return new int []{leftIdx, rightIdx}; } return new int []{-1 , -1 }; } public int binarySearch (int [] nums, int target, boolean lower) { int left = 0 , right = nums.length - 1 , ans = nums.length; while (left <= right) { int mid = (left + right) / 2 ; if (nums[mid] > target || (lower && nums[mid] >= target)) { right = mid - 1 ; ans = mid; } else { left = mid + 1 ; } } return ans; } }
209、长度最小的子数组
题目描述:给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0
示例:
1 2 3 输入:target = 7, nums = [2,3,1,2,4,3] 输出:2 解释:子数组 [4,3] 是该条件下的长度最小的子数组。
思路一:暴力求解 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 minSubArrayLen (int target, int [] nums) { int result = Integer.MAX_VALUE; int sum = 0 ; int sublength = 0 ; for (int i = 0 ; i < nums.length ; i++){ sum = 0 ; for (int j = i ; j < nums.length;j++){ sum += nums[j]; if (sum>= target ){ sublength = j - i + 1 ; result = result < sublength ? result : sublength; break ; } } } return result == Integer.MAX_VALUE ?0 :result; } }
时间复杂度:O(n^2 ),其中 n是数组的长度。需要遍历每个下标作为子数组的开始下标,对于每个开始下标,需要遍历其后面的下标得到长度最小的子数组。
空间复杂度:O(1)
思路二:滑动窗口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Solution { public int minSubArrayLen (int s, int [] nums) { int left = 0 ; int sum = 0 ; int result = Integer.MAX_VALUE; for (int right = 0 ;right < nums.length ; right++){ sum += nums[right]; while (sum >= s){ result = Math.min(result , right - left + 1 ); sum -= nums[left++]; } } return result == Integer.MAX_VALUE ? 0 :result; } }
复杂度分析
这个题目按照题目要求模拟填入过程就可以了:
主要难点在于四个”指针”left、right、top、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 25 26 27 class Solution { public int [][] generateMatrix(int n) { int left = 0 , right = n-1 , top = 0 , bottom = n-1 ; int [][] Mat = new int [n][n]; int end = n*n; int num = 1 ; while (num <= end){ for (int i = left ;i <= right; i++){ Mat[top][i] = num++; } top++; for (int i = top ; i <= bottom; i++){ Mat[i][right] = num++; } right--; for (int i = right ; i >= left; i--){ Mat[bottom][i] = num++; } bottom--; for (int i = bottom ; i >= top; i--){ Mat[i][left] = num++; } left++; } return Mat; } }