二分查找
需求:给定一个由 n 个元素组成的有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回-1。
尝试直接遍历
public class ArraySearch {
public static void main(String[] args) {
int[] nums = {-1,0,3,5,9,12};
int target = 9;
// int target = 2;
int result = searchArrayElement(nums, target);
System.out.println(result);
}
public static int searchArrayElement(int[] nums, int target){
for (int i = 0; i < nums.length; i++) {
if(nums[i] == target){
return i;
}
}
return -1;
}
}
尝试二分查找
public class ArraySearch {
public static void main(String[] args) {
int[] nums = {-1,0,3,5,9,12};
int target = 9;
// int target = 2;
int result = searchArrayElementBinary(nums, target);
System.out.println(result);
}
public static int searchArrayElementBinary(int[] nums, int target){
int left = 0;
int right = nums.length -1;
while(left <= right){
int midIndex = (right + left) / 2;
if(nums[midIndex] < target){
left = midIndex + 1;
}else if(nums[midIndex] > target){
right = midIndex - 1;
}else {
return midIndex;
}
}
return -1;
}
}
这里是将数组nums的合法区间定义为左闭右闭区间,区间边界的定义方式决定了while循环的控制条件中的比较运算符为’<=',而且因为每次循环二分后的区间都是定义为左右闭合区间所以当target大于或小于nums[midIndex]时,在新的区间范围内搜索肯定不会再包括nums[midIndex]的值,所以新的left = midIndex + 1
而新的right = midIndex - 1
。
二分查找改进
为了避免当 target 小于nums[0]或target大于nums[nums.length - 1]时多次循环运算,可以在方法开始时加入判断
if (target < nums[0] || target > nums[nums.length - 1]) {
return -1;
}
为了防止数组中间位置的索引在计算时造成整型数据溢出可以优化为int midIndex = left + ((right - left) >> 1);
整体改进后的二分查找的算法
public class ArraySearch {
public static void main(String[] args) {
int[] nums = {-1,0,3,5,9,12};
int target = 9;
// int target = 2;
int result = searchArrayElementBinary(nums, target);
System.out.println(result);
}
public static int searchArrayElementBinary(int[] nums, int target){
if (target < nums[0] || target > nums[nums.length - 1]) {
return -1;
}
int left = 0;
int right = nums.length -1;
while(left <= right){
// int midIndex = (right + left) / 2;
int midIndex = left + ((right - left) >> 1);
if(nums[midIndex] < target){
left = midIndex + 1;
}else if(nums[midIndex] > target){
right = midIndex - 1;
}else {
return midIndex;
}
}
return -1;
}
}
移除数组元素
需求:给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不需要考虑数组中超出新长度后面的元素。
示例:给定 nums = [0,1,2,2,3,0,4,2], val = 2, 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。
尝试利用两次for循环进行暴力求解
未考虑数组length为final常量值的情况
public class DeletElementFromArray_27 {
public static void main(String[] args){
int[] nums = {0,1,2,2,3,0,4,2};
int val = 2;
int result = newLength(nums, val);
System.out.println(result);
}
public static int newLength(int[] nums, int val){
for (int i = 0; i < nums.length; i++) {
if(nums[i] == val){
// 从i+1开始遍历剩余数据来覆盖前面的值
for (int j = i + 1; j < nums.length; j++){
nums[j-1] = nums[j];
}
i--;
// count++;
nums.length--;
}
}
// return nums.length - count;
return nums.length;
}
}
本来是想在内循环中利用nums.length–缩短遍历的数组长度,但是nums.length是final常量值不能被赋值,所以需要在方法一开始将nums.length存为一个变量int length = nums.length;
然后就可以对length进行更改。
更改后的暴力求解
public class DeletElementFromArray_27 {
public static void main(String[] args){
int[] nums = {0,1,2,2,3,0,4,2};
int val = 2;
int result = newLength(nums, val);
System.out.println(result);
}
public static int newLength(int[] nums, int val){
int length = nums.length;
for (int i = 0; i < length; i++) {
if(nums[i] == val){
// 从i+1开始遍历剩余数据来覆盖前面的值
for (int j = i + 1; j < length; j++){
nums[j-1] = nums[j];
}
i--;
// count++;
length--;
}
}
// return nums.length - count;
return length;
}
}
双指针解法
首先定义一个快指针和一个慢指针,快指针用来确定新数组的元素,慢指针用来确定需要被覆盖的元素位置,只需要一个for循环,当快指针不等于val的值时将快指针的值赋给慢指针,然后两个指针同时前进,当快指针遇到val值,慢指针不动快指针继续前进当再次遇到不等于val的值就再将当前的值赋给慢指针。
public class DeletElementFromArray_27 {
public static void main(String[] args){
int[] nums = {0,1,2,2,3,0,4,2};
int val = 2;
// int result = newLength(nums, val);
int result = newLengthBothPointer(nums, val);
System.out.println(result);
}
public static int newLengthBothPointer(int[] nums, int val){
// int fastPointer = 0;
int slowPointer = 0;
for (int fastPointer = 0; fastPointer < nums.length; fastPointer++) {
if(nums[fastPointer] != val){
nums[slowPointer] = nums[fastPointer];
slowPointer++;
}
}
return slowPointer;
}
}