思路:因为数组是升序排列的,那么可以通过二分来以O(logN)的复杂度查找target,如果遍历每一个数的话,那就是O(N)了。那么二分的话,首先就是要明确对区间的定义是左闭右闭的区间,还是左闭右开的区间。然后两个int想加,可能越界,最好处理一下,注意题目的数据范围。然后就是除法操作可以用移位运算符代替。进入循环之后,更新区间的时候是直接等于middle还是middle-1?因为区间是左闭右闭的,所以应该是middle-1,不然就重复判断之前的数了。还有就是这道题好像很多同学容易TLE,应该是因为mid更新放到了循环外面吧
class Solution {
public int search(int[] nums, int target) {
// int mid = nums.length / 2;
// while (mid >= 0 && mid <= nums.length - 1) {
// if (nums[mid] == target) {
// return mid;
// }
// if (nums[mid] < target) {
// mid = (mid + nums.length - 1) / 2;
// }
// if (nums[mid] > target) {
// mid = mid / 2;
// }
// }
// return -1;
if (target < nums[0] || target > nums[nums.length - 1]) {
return -1;
}
int left = 0;
int right = nums.length - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (nums[mid] > target) {
// 不包含mid 因为已经判断过了
right = mid - 1;
} else if (nums[mid] < target) {
left = mid + 1;
} else {
return mid;
}
}
return -1;
}
}
leetcode.com/problems/re… 27. 移除元素
思路:暴力解法就是两个for循环,时间复杂度O(n^2)。这道题目用双指针显然会好很多,因为可以只用遍历一遍数组,复杂度O(N^2)。那么双指针做法就是定义两个指针,一个快一个慢,都从0开始,快指针用来找新数组也就是移除元素之后的数组中的值,而慢指针就是新数组的下标。
class Solution {
public int removeElement(int[] nums, int val) {
int slow = 0;
int fast = 0;
// 快慢指针同步走
while (fast < nums.length) {
// 如果找到目标元素,快指针移动到后面一个,然后交换快慢指针的值,覆盖掉目标元素
if (nums[fast] != val) {
// 把需要的元素复制给新数组下标
nums[slow] = nums[fast];
slow++;
}
fast++;
}
return slow;
}
}
总结:实际上二分并不是数组有序的情况下才能使用,有一些局部升序降序,但是总体可能无序的数组也是可以用到二分的,这个以后碰到对应题目再聊。