文章目录
69.x的平方根
去除x0和x1的情况,然后从1到x进行二分查找
public class Solution {
public int mySqrt(int x) {
if (x == 0 || x == 1) return x;
int left = 1;
int right = x;
while (left <= right) {
int mid = left + (right - left) / 2;//防止越界,用减法或者位运算
// int mid = (right + left) >> 1;
if (mid > x / mid) right = mid - 1;//除法防止越界
else left = mid + 1;
}
return right;
}
}
牛顿迭代法:
参考题解
class Solution {
public int mySqrt(int x) {
long r = x;
while (r * r > x) {
r = (r + x / r) / 2;
}
return (int)r;
}
}
367.有效的完全平方数
二分查找
class Solution {
public boolean isPerfectSquare(int num) {
if (num == 1) return true;
long left = 2;
long right = num / 2;
while (left <= right) {
long mid = (left + right) >> 1;
if (mid * mid == num) return true;
else if (mid > num / mid) right = mid - 1;
else left = mid + 1;
}
return false;
}
}
牛顿迭代法
迭代求算数平方根,如果算数平方根的平方还是num,说明是完全平方数
public class Solution {
public boolean isPerfectSquare(int num) {
if (num < 2) return true;
long a = num;
while (a * a > num) {
a = (a + num / a) / 2;
}
return a * a == num;
}
}
33.搜索旋转排序数组
二分查找:每次查找必有一边是有序的!找到有序的一边,判断target在不在里面
class Solution {
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while (left <= right) {
int mid = (left + right) >> 1;
if (target == nums[mid]) return mid;//找到结果
//前半段有序(可能的情况:456123,444123,因为旋转前是有序的,所以这个条件一定满足)
if (nums[left] <= nums[mid]) {
//taget在前半段,mid位置已经判断了,left位置还需要判断
if (target < nums[mid] && target >= nums[left]) {
right = mid - 1;
} else {//不在前半段
left = mid + 1;
}
} else {//后半段有序(可能情况:561234)
//target在后半段,mid位置已经判断了,right位置还需要判断
if (target > nums[mid] && target <= nums[right]) {
left = mid + 1;
} else {//不在后半段
right = mid - 1;
}
}
}
//没找到
return -1;
}
}
74.搜索二维矩阵
二分查找:
将二维数组当成一维进行查找
public class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return false;
int m = matrix.length;
int n = matrix[0].length;
int left = 0;
int right = m * n - 1;
while (left <= right) {
int mid = (left + right) >>> 1;
if (target == matrix[mid / n][mid % n]) return true;
if (target > matrix[mid / n][mid % n]) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return false;
}
}
右上角为起点的查找,查找状态树是一棵二叉搜索树
public class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return false;
int m = matrix.length;
int n = matrix[0].length;
int i = 0;
int j = n - 1;
while (i < m && j >= 0) {
if (matrix[i][j] == target) return true;
else if ( target>matrix[i][j]) i++;
else j--;
}
return false;
}
}
153.寻找旋转排序数组中的最小值
如果nums[left] <= nums[right]
说明这一段有序,且是我们选择的包含拐点的部分
如果没有序,二分查询无序部分
class Solution {
public int findMin(int[] nums) {
int left = 0;
int right = nums.length - 1;
while (left <= right) {
if (nums[left] <= nums[right]) {
return nums[left];
}
int mid = (left + right) >> 1;
//有序在左边,就去右边查找
if (nums[mid] >= nums[left]) {
left = mid + 1;
} else {
right = mid;
}
}
return nums[left];
}
}
class Solution {
public int findMin(int[] nums) {
int left = 0;
int right = nums.length - 1;
while (left < right) {
int mid = (left + right) >> 1;
//后半段无序
if (nums[mid] > nums[right]) {
left = mid + 1;
} else {
right = mid;
}
}
return nums[left];
}
}
744.寻找比目标字母大的最小字母
题意:给定一个循环有序的字符数组 letters 和一个字符 target,要求找出 letters 中大于 target 的最小字符,如果
找不到就返回第 1 个字符。
public class Solution {
public char nextGreatestLetter(char[] letters, char target) {
int left = 0;
int right = letters.length - 1;
while (left <= right) {
int mid = (left + right) >> 1;
if (letters[mid] <= target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return left < letters.length ? letters[left] : letters[0];
}
}
540.有序数组中的单一元素
针对偶数位的二分查找
计算中点,如果中点下标为奇数,让其减1,保证mid是每一组两个数的开头
比较mid下标值和mid+1下标值,如果相同说明这个数有两个,left右移两位,否则这个位置及之前出现了1个数的,将right设置为mid
public class Solution {
public int singleNonDuplicate(int[] nums) {
int left = 0;
int right = nums.length - 1;
while (left < right) {
int mid = (left + right) >> 1;
if (mid % 2 == 1) {
mid--;//保证查找区间大小保持奇数,保证mid是一组的开始
}
if (nums[mid] == nums[mid + 1]) {
left = mid + 2;
} else {
right = mid;
}
}
return nums[left];
}
}
278.第一个错误的版本
二分查找,如果查找节点是错误版本,则第一个错误点在当前节点及之前;如果查找节点不是错误版本,则第一个错误点在当前节点之后
public class Solution extends VersionControl {
public int firstBadVersion(int n) {
int left = 1;
int right = n;
while (left < right) {
int mid = (left + right) >>> 1;
if (isBadVersion(mid)) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
}
34.在排序数组中查找元素的第一个和最后一个位置
通过二分查找找到target,然后移动两个指针找到左右边界
public class Solution {
public int[] searchRange(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while (left <= right) {
int mid = (left + right) >>> 1;
if (nums[mid] == target) {
int l = mid;//左边界
int r = mid;//右边界
while (l - 1 >= 0 && nums[l] == nums[l - 1]) {
l--;
}
while (r + 1 < nums.length && nums[r] == nums[r + 1]) {
r++;
}
return new int[]{l, r};
} else if (nums[mid] > target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return new int[]{-1, -1};
}
}