思路:基本的二分查找方法。
关键点:在while循环中的L
所谓的:
**左闭右闭:**就是R=size-1;R指向数组最后一个元素;
**左闭右开:**就是R=size; R指向数组最后一个元素的下一个。
之后的循环中保持这个规律即可。
左闭右闭
class Solution {
public int search(int[] nums, int target) {
// 左闭右闭
int size = nums.length;
int L = 0;
int R = size - 1;
while(R>=L){ // 因为最右边的一个元素是有效的所以存在L=R的情况,因此要保留。
int mid = L + ((R-L)>>1);
if(nums[mid]>target){
R = mid - 1;
}
else if(nums[mid] < target){
L = mid + 1;
}
else{
return mid;
}
}
return -1;
}
}
左闭右闭
class Solution {
public int search(int[] nums, int target) {
// 左闭右开
// whlie(L
int size = nums.length;
int L = 0;
int R = size;
while(L<R){
int mid = L + ((R - L)>>1);
if(nums[mid] > target){
R = mid;
}
else if(nums[mid] < target){
L = mid + 1;
}
else{
return mid;
}
}
return -1;
}
}
思路:题目要求的复杂度是logn。想到二分查找
关键点:二分查找中选择使用左闭右开的方法,这样可以避免另外加一个变量来记录target不在nums的情况。
// java
class Solution {
public int searchInsert(int[] nums, int target) {
// 左闭右开
int size = nums.length;
int L = 0;
int R = size;
while(L<R){
int mid = L + ((R-L)>>1);
if(nums[mid] > target){
R = mid;
}
else if(nums[mid] < target){
L = mid + 1;
}
else{
return mid;
}
}
return R;
}
}
// CPP
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int L = 0;
int R = nums.size();
while(R > L){
int mid = L + ((R - L) >> 1);
if(nums[mid] > target){
R = mid;
}
else if(nums[mid] < target){
L = mid + 1;
}else{
return mid;
}
}
return R;
}
};
思路: 看到题目要求O(logn)
。第一反应就是二分查找。但是这一题关键是一步二分查找不行,得需要两次,一次找到左边界,另一次找到右边界。由于数组是递增的,因此分为两种情况:
左边界:就是找到第一个大于等于target的位置;
右边界:找到第一个大于等于target+1的位置。
细节很繁琐。
关键点:。target >= num[mid]
。这里就是找到
不同于传统的二分查找,最后的返回出口是target == num[mid]
。
分别通过if target <= nums[mid]找到左边界;if target >= nums[mid] 找到右边界;分情况讨论。
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int left = binarySearch(nums, target);
int right = binarySearch(nums, target+1)-1;
if(right>=left && nums[left] == target && right <= nums.size()){
return {left, right};
}
return {-1, -1};
}
int binarySearch(vector<int>& nums, int target){
int L = 0;
int R = nums.size() - 1;
while(L <= R){
int mid = L + ((R - L) >> 1);
if(target <= nums[mid]){ // 关键
R = mid - 1;
}
else{
L = mid + 1;
}
}
return L;
}
};
class Solution {
public int[] searchRange(int[] nums, int target) {
// 基本思想能够想到,但是具体的细节有很多要考虑
// 这一题,再次认识里面的符号的作用>=
int left = binarySearch(nums, target); // 寻找左边第一个大于>=target的数,全是大于则没有,有了等于就是第一个。
int right = binarySearch(nums, target+1)-1; // 寻找右边第一个大于target的数
if(left<=right && right<nums.length && nums[left]==target && nums[right]==target){
return new int[] {left, right};
}
return new int[] {-1, -1};
}
public int binarySearch(int[] nums, int target){
int L = 0;
int R = nums.length - 1;
while(L<=R){
int mid = L + ((R-L)>>1);
if(nums[mid] < target){
L = mid+1;
}
else if(nums[mid] >= target){ // 注意这里的变化,要的是>= 这样会接着执行指导左边第一个target,或者是左边第一个大于target的数。
R = mid-1;
}
}
return L;
}
}
思路:被题目迷惑了。’这道题目不单单返回最后的长度,还要将里面对应的val删除。
注意:还要删除里面的对应值为val的元素。
解法一:暴力
class Solution {
public int removeElement(int[] nums, int val) {
// 半天没读懂题目,明确说返回新数组的长度就好了。
// 先来一个暴力解法:
// 两层for循环,找到对应的val之后就将后面的元素整体往前移一位,
// 同时,i--;size-- 因为整体都少了一个
// 最后返回size。
int size = nums.length;
for(int i=0;i<size;i++){
if(nums[i] == val){
for(int j = i+1;j<size;j++){
nums[j-1] =nums[j];
}
i--;
size--;
}
}
return size;
}
}
解法二:双指针(看了代码随想录)
class Solution {
public int removeElement(int[] nums, int val) {
// 单单返回最后的长度还不行,还要将里面的元素删除。
// 双指针解法;快慢指针
// 画图就好理解了。
int size= nums.length;
int slow = 0;
for(int fast=0;fast<size;fast++){
if(nums[fast] != val){
nums[slow] = nums[fast];
slow++;
}
}
return slow;
}
}