二分从简单到中等
leetcode 35. 搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。
示例 1:
输入: [1,3,5,6], 5
输出: 2
示例 2:
输入: [1,3,5,6], 2
输出: 1
示例 3:
输入: [1,3,5,6], 7
输出: 4
示例 4:
输入: [1,3,5,6], 0
输出: 0
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/search-insert-position
java代码解答
class Solution {
public int searchInsert(int[] nums, int target) {
int low=0;
int high=nums.length-1;
int mid;
while(low<high){
//位运算优先级低于+号,尽量不要用low+high再右移,可能low+high超过数据类型的范围
mid=low+((high-low)>>1);
if(target>nums[mid]){
low=mid+1;
}else if(target<nums[mid]){
high=mid-1;
}else{
return mid;
}
}
//跳出来的时候是low和high相等的时候
if(nums[low]<target){
return low+1;
}else{
return low;
}
}
}
69. x 的平方根
实现 int sqrt(int x) 函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
示例 1:
输入: 4
输出: 2
示例 2:
输入: 8
输出: 2
说明: 8 的平方根是 2.82842…,
由于返回类型是整数,小数部分将被舍去。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sqrtx
java这样硬解会超时
class Solution {
public int mySqrt(int x) {
int i;
for(i=0;i*i<x;i++){
continue;
}
if(i*i==x){
return i;
}
return i-1;
}
}
下面做法用到了函数,其实实际要求肯定不是想让这个
class Solution {
public int mySqrt(int x) {
int i =(int)Math.sqrt(x);
return i;
}
}
下面是错误的二分,因为数字非常大的时候,mid*mid<x始终就是true
class Solution {
public static int mySqrt(int x) {
int low=0;
int high=x;
int mid;
while(low<high){
mid=low+((high-low)>>1);
if(mid*mid<x){
low=mid+1;
}else if(mid*mid>x){
high=mid-1;
}else{
return mid;
}
}
if(low*low<=x){
return low;
}
else{
return low-1;
}
}
}
用double避免了算不出mid*mid,虽然过了,但是真真的想法应该不是想让你这样搞
public static int mySqrt(int x) {
int low=0;
int high=x;
double mid;
while(low<high){
mid=low+((high-low)>>1);
if(mid*mid<x){
low=(int)mid+1;
}else if(mid*mid>x){
high=(int)mid-1;
}else{
return (int)mid;
}
}
if(low*low<=x){
return low;
}
else{
return low-1;
}
}
这样做应该最合适
class Solution {
public static int mySqrt(int x) {
//防止x/0情况发生
if(x==0||x==1){
return x;
}
int low=0;
int high=x;
int mid;
while(low<high){
mid=low+((high-low)>>1);
if(x/mid>mid){
low=mid+1;
}else if(x/mid<mid){
high=mid-1;
}else{
return mid;
}
}
if(low*low<=x){
return low;
}
else{
return low-1;
}
}
}
官方给了另一种解法
「袖珍计算器算法」是一种用指数函数 exp\expexp 和对数函数 ln\lnln 代替平方根函数的方法。我们通过有限的可以使用的数学函数,得到我们想要计算的结果。
我们将 x\sqrt{x}x
写成幂的形式 x1/2x^{1/2}x1/2,再使用自然对数 eee 进行换底,即可得到
x=x1/2=(elnx)1/2=e12lnx\sqrt{x} = x^{1/2} = (e ^ {\ln x})^{1/2} = e^{\frac{1}{2} \ln x} x
=x1/2=(elnx)1/2=e21lnx
这样我们就可以得到 x\sqrt{x}x
的值了。
注意: 由于计算机无法存储浮点数的精确值(浮点数的存储方法可以参考 IEEE 754,这里不再赘述),而指数函数和对数函数的参数和返回值均为浮点数,因此运算过程中会存在误差。例如当 x=2147395600x = 2147395600x=2147395600 时,e12lnxe^{\frac{1}{2} \ln x}e21lnx 的计算结果与正确值 463404634046340 相差 10−1110^{-11}10−11,这样在对结果取整数部分时,会得到 463394633946339 这个错误的结果。
因此在得到结果的整数部分 ans\textit{ans}ans 后,我们应当找出 ans\textit{ans}ans 与 ans+1\textit{ans} + 1ans+1 中哪一个是真正的答案。
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/sqrtx/solution/x-de-ping-fang-gen-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public int mySqrt(int x) {
if (x == 0) {
return 0;
}
int ans = (int) Math.exp(0.5 * Math.log(x));
return (long) (ans + 1) * (ans + 1) <= x ? ans + 1 : ans;
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/sqrtx/solution/x-de-ping-fang-gen-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
static double log(double a)
返回的自然对数(以 e为底) double值。
static double exp(double a)
返回欧拉的数字 e提高到一个 double价值。 应该意思就是求指数
50. Pow(x, n)
实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn)。
示例 1:
输入:x = 2.00000, n = 10
输出:1024.00000
示例 2:
输入:x = 2.10000, n = 3
输出:9.26100
示例 3:
输入:x = 2.00000, n = -2
输出:0.25000
解释:2-2 = 1/22 = 1/4 = 0.25
提示:
-100.0 < x < 100.0
-231 <= n <= 231-1
-104 <= xn <= 104
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/powx-n
java解答
快速幂,其实发现如果用递归思路非常明显,用迭代思路就没那么好看了,但是两个都可以,想明白了就都一样
/*
快速幂加递归
递归三步 递归的思路解决 找子问题 找终止条件 写递归条件*/
/*
快速幂加递归
递归三步 递归的思路解决 找子问题 找终止条件 写递归条件*/
class Solution {
public double myPow(double x, int n) {
if(n==0||x==1){
return 1;
}
if(x==0){
return 0;
}
//就是这句话没有导致数组越界了
if (n == Integer.MIN_VALUE) return myPow(x, n + 1) / x;
if(n<0){
return 1/kmFun(x,-n);
}
return kmFun(x,n);
}
double kmFun(double x,int n){
终止条件
if(n==1){
return x;
}
if(n%2!=0){
//奇数的时候
double mid=kmFun(x,n/2);
return mid*mid*x;
}
//如果是偶数,再递归
double mid=kmFun(x,n/2);
return mid*mid;
}
}
74 . 搜索二维矩阵
题目内容
编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:
每行中的整数从左到右按升序排列。
每行的第一个整数大于前一行的最后一个整数。
示例 1:
输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3
输出:true
示例 2:
输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 13
输出:false
提示:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 100
-104 <= matrix[i][j], target <= 104
通过次数89,098
提交次数216,622
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/search-a-2d-matrix
java解答 虽然解法时间0ms,但是感觉能把二维矩阵变成一维数组,然后二分,这样效果说不定更好
/*
两次二分,找到中间的*/
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
//先二分找到所在行
//行数
int m=matrix.length;
//列数
int n=matrix[0].length;
//二分找到行
int left=0;
int right=m-1;
while(left<right){
//除二换成位运算也蛮好的,但记得优先级,加括号
int mid=left+(right-left)/2;
if(target>matrix[mid][n-1]){
left=mid+1;
}else if(target<matrix[mid][n-1]){
//这里只能等于mid,肯定不能mid-1,否则正确的行就会变没
right=mid;
}else{
return true;
}
}
//此时后出来的left就是确定的行
int hang=left;
left=0;
right=n-1;
while(left<right){
int mid=left+(right-left)/2;
if(target>matrix[hang][mid]){
left=mid+1;
}else if(target<matrix[hang][mid]){
//这里只能等于mid,肯定不能mid-1,否则正确的行就会变没
right=mid;
}else{
return true;
}
}
//防止只有一个的时候
if(matrix[hang][left]==target){
return true;
}
return false;
}
}
一次二分实现
/*
一次二分*/
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
//先二分找到所在行
//行数
int m=matrix.length;
//列数
int n=matrix[0].length;
//二维数组转化一维数组,然后再二分查找,效率会更高
int left=0;
int right=m*n-1;
while(left<right){
//除二换成位运算也蛮好的,但记得优先级,加括号
int mid=left+((right-left)>>1);
if(target>matrix[mid/n][mid%n]){
left=mid+1;
}else if(target<matrix[mid/n][mid%n]){
//这里只能等于mid,肯定不能mid-1,否则正确的行就会变没
right=mid;
}else{
return true;
}
}
if(target==matrix[left/n][left%n]){
return true;
}
return false;
}
}