704. 二分查找
题目
给定一个 n
个元素有序的(升序)整型数组 nums
和一个目标值 target
,写一个函数搜索 nums
中的 target
,如果目标值存在返回下标,否则返回 -1
。
示例 1:
输入:nums
= [-1,0,3,5,9,12],target
= 9 输出: 4 解释: 9 出现在nums
中并且下标为 4
示例 2:
输入:nums
= [-1,0,3,5,9,12],target
= 2 输出: -1 解释: 2 不存在nums
中因此返回 -1
提示:
- 你可以假设
nums
中的所有元素是不重复的。 n
将在[1, 10000]
之间。nums
的每个元素都将在[-9999, 9999]
之间。
思路
1. 关键词:升序、整型、不重复、返回下标即可。
2. 二分查找:关键在mid和while循环条件,mid不能溢出
3. 代码选择闭区间,right = nums.length - 1,
4. while循环根据闭区间选择<=
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;
if(target < nums[mid]) {
right = mid - 1;
}
if(target > nums[mid]) {
left = mid + 1;
}
if(target == nums[mid]) {
return mid;
}
}
return -1;
}
}
35.搜索插入位置
题目
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。
示例 1:
- 输入: [1,3,5,6], 5
- 输出: 2
示例 2:
- 输入: [1,3,5,6], 2
- 输出: 1
示例 3:
- 输入: [1,3,5,6], 7
- 输出: 4
示例 4:
- 输入: [1,3,5,6], 0
- 输出: 0
思路
1. 要点:无重复、升序、插入位置
2. 分析:若找到,nums[mid] = target,则返回mid即可
3. 若没有,找到第一个大于他的位置,
4. 返回值可以超出边界
5. 综上所述,应用开区间,while(<).
class Solution {
public int searchInsert(int[] nums, int target) {
int l = 0, r = nums.length;
while (l < r) {
int mid = l + (r - l) / 2;
if (target == nums[mid]) {
return mid;
}
else if (target < nums[mid]) {
r = mid;
}
else if (target > nums[mid]) {
l = mid + 1;
}
}
return r;
}
}
34. 在排序数组中查找元素的第一个和最后一个位置
题目
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
进阶:你可以设计并实现时间复杂度为 $O(\log n)$ 的算法解决此问题吗?
示例 1:
- 输入:nums = [5,7,7,8,8,10], target = 8
- 输出:[3,4]
示例 2:
- 输入:nums = [5,7,7,8,8,10], target = 6
- 输出:[-1,-1]
示例 3:
- 输入:nums = [], target = 0
- 输出:[-1,-1]
#思路
1. 查找左右边界,升序,可以重复
2. 查找左边界:采用闭区间,最终变化结果是left=right+1,最终判断left是不是边界
3. 查找有边界:采用闭区间,最终是left=right+1,最终判断right是不是边界
class Solution {
public int[] searchRange(int[] nums, int target) {
int[] ans = new int[2];
ans[0] = searchLeft(nums, target);
ans[1] = searchRight(nums, target);
return ans;
}
public int searchLeft(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while(left <= right) {
int mid = left + (right - left) / 2;
if(target <= nums[mid]) {
right = mid - 1;
}
else {
left = mid + 1;
}
}
if(left >= nums.length || left < 0) return -1;
return nums[left] == target ? left : -1;
}
public int searchRight(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while(left <= right) {
int mid = left + (right - left) / 2;
if(target >= nums[mid]) {
left = mid + 1;
}
else {
right = mid - 1;
}
}
if(right >= nums.length || right < 0) return -1;
return nums[right] == target ? right : -1;
}
}
27. 移除元素
题目
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
示例 1: 给定 nums = [3,2,2,3], val = 3, 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 你不需要考虑数组中超出新长度后面的元素。
示例 2: 给定 nums = [0,1,2,2,3,0,4,2], val = 2, 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。
你不需要考虑数组中超出新长度后面的元素。
思路
1. 快指针始终指向非val位置与慢指针交换。
class Solution {
public int removeElement(int[] nums, int val) {
int slow = 0;
for(int fast = 0; fast < nums.length; fast++) {
if(val != nums[fast]) {
nums[slow++] = nums[fast];
}
}
return slow;
}
}
class Solution {
public int removeElement(int[] nums, int val) {
int left = 0, right = nums.length - 1;
while(left <= right) {
if(nums[left] == val) {
nums[left] = nums[right];
right --;
} else {
left ++;
}
}
return left;
}
}
977.有序数组的平方
题目
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例 1:
- 输入:nums = [-4,-1,0,3,10]
- 输出:[0,1,9,16,100]
- 解释:平方后,数组变为 [16,1,0,9,100],排序后,数组变为 [0,1,9,16,100]
示例 2:
- 输入:nums = [-7,-3,2,3,11]
- 输出:[4,9,9,49,121]
思路
1. 平方数两头大中间小。
2. 首尾双指针,将大的排到后面。
class Solution {
public int[] sortedSquares(int[] nums) {
int left = 0, right = nums.length - 1;
int[] res = new int[nums.length];
int index = nums.length - 1;
while(left <= right) {
if(nums[left] * nums[left] <= nums[right] * nums[right]) {
res[index--] = nums[right] * nums[right];
right --;
}
else {
res[index--] = nums[left] * nums[left];
left ++;
}
}
return res;
}
}