文章目录
704. 查找排序数组(最基本的二分查找)
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
class Solution {
/**
* 二分法模板
* @param arr
* @param target
* @return
*/
public static int binarySearch(int[] arr, int target) {
if (arr.length == 0) {
return -1;
}
int start = 0;
int end = arr.length - 1;
int mid;
// start和 end相邻的时候退出循环
while (start + 1 < end) {
mid = start + (end - start) / 2;
if (arr[mid] == target) {
return mid;
} else if (arr[mid] < target) {
start = mid;
} else {
end = mid;
}
}
if (arr[start] == target) {
return start;
}
if (arr[end] == target) {
return end;
}
return -1;
}
/**
* 递归查找
* @param nums
* @param target
* @return
*/
public int search(int[] nums, int target) {
return recursionSearch(nums, 0, nums.length - 1, target);
}
public int recursionSearch(int[] nums, int l, int r, int target) {
if (l > r) {
return -1;
}
int mid = l + (r - l) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] > target) {
return recursionSearch(nums, l, mid - 1, target);
} else {
return recursionSearch(nums, mid + 1, r, target);
}
}
}
34. 在排序数组中查找元素的第一个和最后一个位置
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。你的算法时间复杂度必须是 O(log n) 级别。如果数组中不存在目标值,返回 [-1, -1]。
class Solution {
public int[] searchRange(int[] nums, int target) {
int[] res = new int[2];
res[0] = findFirst(nums, target);
res[1] = findLast(nums, target);
return res;
}
public int findFirst(int[] arr, int target) {
if (arr.length == 0) {
return -1;
}
int start = 0;
int end = arr.length - 1;
int mid;
while (start + 1 < end) {
mid = start + (end - start) / 2;
if (arr[mid] == target) {
//1、如果是任意位置,在此返回
//return mid;
//2、如果是找第一个
end = mid;
//3、如果是找最后一个
//start = mid;
} else if (arr[mid] < target) {
start = mid;
} else {
end = mid;
}
}
/*first position这个判断在前*/
if (arr[start] == target) {
return start;
}
/*last position这个判断在前*/
if (arr[end] == target) {
return end;
}
return -1;
}
public int findLast(int[] arr, int target) {
if (arr.length == 0) {
return -1;
}
int start = 0;
int end = arr.length - 1;
int mid;
while (start + 1 < end) {
mid = start + (end - start) / 2;
if (arr[mid] == target) {
//1、如果是任意位置,在此返回
//return mid;
//2、如果是找第一个
// end = mid;
//3、如果是找最后一个
start = mid;
} else if (arr[mid] < target) {
start = mid;
} else {
end = mid;
}
}
/*last position这个判断在前*/
if (arr[end] == target) {
return end;
}
/*first position这个判断在前*/
if (arr[start] == target) {
return start;
}
return -1;
}
}
35. 搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。你可以假设数组中无重复元素。
/**
* 输入: [1,3,5,6], 5
* 输出: 2
*
* 输入: [1,3,5,6], 2
* 输出: 1
*
* 输入: [1,3,5,6], 0
* 输出: 0
*
* 在数组中找到一个数,当这个数 >= target 时,此位置就是插入的位置
* 如果数组中有重复的,根据情况看放在整体相等元素的前面,还是后面
*/
class Solution {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 3, 4, 5};
System.out.println(searchInsert(arr, 3));
}
public static int searchInsert(int[] nums, int target) {
if (nums.length == 0) {
return -1;
}
int start = 0;
int end = nums.length - 1;
int mid;
while (start + 1 < end) {
mid = start + (end - start) / 2;
if (nums[mid] == target) {
// 数组中无重复元素,找到直接返回
return mid;
// 如果有重复的,放到重复元素的前面就end = mid,后面就start = mid
// start = mid;
// end = mid;
} else if (nums[mid] < target) {
start = mid;
} else {
end = mid;
}
}
// 跳出循环没有返回,则说明这个数可能在 start或者 end位置上
// 如果有重复的,放在重复的前面先判断start,放在后面先判断end
if (nums[start] >= target) {
return start;
} else if (nums[end] >= target) {
return end;
} else {
// 都没有>=target的,则target比所有数都大,插入到末尾
return end + 1;
}
}
}
36. 第一个错误版本
public class Solution extends VersionControl {
public int firstBadVersion(int n) {
int start = 1;
int end = n;
while (start + 1 < end) {
int mid = start + (end - start) / 2;
if (isBadVersion(mid)) {
// 如果当前版本是错误的,end = mid
end = mid;
} else {
// 如果当前版本是好的,start = mid
start = mid;
}
}
// 跳出循环,start和end相邻,判断两个中哪一个是错误的
if (isBadVersion(start)) {
return start;
} else {
return end;
}
}
}
class VersionControl {
/**
* 判断当前版本是否出错
* @param version
* @return
*/
public boolean isBadVersion(Integer version) {
return true;
}
}
162. 寻找峰值
峰值元素是指其值大于左右相邻值的元素。
class Solution {
/**
* 峰值元素是指其值大于左右相邻值的元素。
* @param nums
* @return
*/
public int findPeakElement(int[] nums) {
int start = 0;
int end = nums.length - 1;
while(start + 1 < end){
int mid = start + (end - start)/2;
// 如果当前数小于前面一个数,则当前数左边存在峰值
if(nums[mid] < nums[mid - 1]){
end = mid;
} else {
// 否则右边存在峰值
start = mid;
}
}
if(nums[start] < nums[end]){
return end;
} else {
return start;
}
}
}
33. 搜索旋转排序数组
/**
* 数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2]
* 搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
* 你可以假设数组中不存在重复的元素。
* 你的算法时间复杂度必须是 O(logN) 级别。
*/
class Solution {
public int search(int[] nums, int target) {
if (nums == null || nums.length == 0) {
return -1;
}
int start = 0;
int end = nums.length - 1;
int mid;
while (start + 1 < end) {
mid = start + (end - start) / 2;
if (nums[mid] == target) {
return mid;
}
// mid被分到旋转的部分
if (nums[start] < nums[mid]) {
// target在start和mid之间
if (nums[start] <= target && target <= nums[mid]) {
end = mid;
} else {
// target在mid右边
start = mid;
}
} else { // mid被分到为旋转的部分
// target在mid到end之间
if (nums[mid] <= target && target <= nums[end]) {
start = mid;
} else {
// target在mid左边
end = mid;
}
}
}
if (nums[start] == target) {
return start;
}
if (nums[end] == target) {
return end;
}
return -1;
}
}
153. 搜索旋转排序数组中的最小值(无重复元素)
class Solution {
/**
* @param nums: a rotated sorted array
* @return: the minimum number in the array
*/
public int findMin(int[] nums) {
if (nums == null || nums.length == 0) {
return -1;
}
int start = 0, end = nums.length - 1;
int target = nums[nums.length - 1];
// find the first element <= target
while (start + 1 < end) {
int mid = start + (end - start) / 2;
//如果mid位置上的数字小于等于最右端的数字时,区间向左移动
if (nums[mid] <= target) {
end = mid;
} else {
// 区间右移
start = mid;
}
}
//最终返回start和end位置上较小的数字即可
return Math.min(nums[start], nums[end]);
}
}
class Solution {
public static int findMin(int[] nums) {
if(nums.length == 1){
return nums[0];
}
int l = 0;
int r = nums.length - 1;
while(l < r){
// 中间节点的值
int mid = l + (r - l) / 2;
// 中间位置的值小,则最小值出现在[0 ~ mid]
if(nums[mid] < nums[r]) r = mid;
// mid的值大于r 则最小值出现在[mid+1 ~ r]
else l = mid + 1;
}
return nums[l];
}
}
154. 搜索旋转排序数组中的最小值 (有重复元素)
数组中有最小值,其实这种情况是考察如果有重复元素的最差情况下的时间复杂度
public class Solution {
public int findMin(int[] num) {
// 这道题目在面试中不会让写完整的程序
// 只需要知道最坏情况下 [1,1,1....,1] 里有一个0
// 这种情况使得时间复杂度必须是 O(n)
// 因此写一个for循环就好了。
// 如果你觉得,不是每个情况都是最坏情况,你想用二分法解决不是最坏情况的情况,那你就写一个二分吧。
// 反正面试考的不是你在这个题上会不会用二分法。这个题的考点是你想不想得到最坏情况。
int min = num[0];
for (int i = 1; i < num.length; i++) {
if (num[i] < min)
min = num[i];
}
return min;
}
}
public class Solution {
/**
* @param num: a rotated sorted array
* @return: the minimum number in the array
*/
public int findMin(int[] nums) {
if (nums == null || nums.length == 0) {
return -1;
}
int start = 0, end = nums.length - 1;
while (start + 1 < end) {
int mid = start + (end - start) / 2;
if (nums[mid] == nums[end]) {
// if mid equals to end, that means it's fine to remove end
// the smallest element won't be removed
end--;
} else if (nums[mid] < nums[end]) {
end = mid;
} else {
start = mid;
}
}
if (nums[start] <= nums[end]) {
return nums[start];
}
return nums[end];
}
}
1212

被折叠的 条评论
为什么被折叠?



