14. <tag-数组和二分查找_2>-lt.240-搜索二维矩阵 || + lt.633-平方数之和 +lt.69-Sqrt(x) 1
lt.240-搜索二维矩阵 ||
[案例需求]
优化1. 二分查找法
[思路分析]
-
本题, 从基础的倒序遍历解法上来看, 跟之前做过的一道题lt.74-搜索二维矩阵完全类似
-
这里, 我们采用二分查找法解题;
-
要注意到的是: 与 lt.74-搜索二维矩阵不同,本题没有确保「每行的第一个整数大于前一行的最后一个整数」,因此我们无法采取「两次二分」的做法。只能退而求之,遍历行/列,然后再对列/行进行二分。
-
首先我们对二维数组遍历每一行, 跟倒序遍历相似
-
- 第一层循环, 我们遍历二维数组的每一行,
-
- 如果 某一行末尾的数 < target , 那么由于行升序的原因, 可以直接跳出本次遍历;
-
- 如果 某一行末尾的数 > target , 说明target可能是在这一行, 就在这一行进行二分查找, 取本行的第一个数作为left指针, 最后一个数作为right指针,
-
- 如果前面的二分查找没找到, 就继续下一行的循环;
-
[代码实现]
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
//倒序遍历
for(int i = 0; i < matrix.length; i++){
int L = 0;
int R = matrix[i].length - 1;
if(matrix[i][R] < target) continue;
while(L <= R){
int mid = L + (R - L)/2;
if(matrix[i][mid] == target){
return true;
}else if(matrix[i][mid] < target){
L = mid + 1;
}else if(matrix[i][mid] > target){
R = mid - 1;
}
}
}
return false;
}
}
- 相比前面文章写道的倒序遍历, 其实提高并不是很大, 这里主要是因为采用倒序遍历跟二分法时, 我们都对
target > 每行末尾最后一个数
的这样的行, 做了跳过本行的操作(因为每行是升序的嘛, 最后一个数都小于 target了, 哪还有向前遍历的需要啊), 而在target < 某一行末尾的最后一个数
这样的行里, 我们才对行中的数进行倒序遍历(或二分查找), 倒序遍历和二分查找的差别就是在这样行里, 所以优化提升非常有限;
优化2. 利用单调性(把
行升序
和列升序
两个条件同时利用起来)
[思路分析]
[代码实现]
//单调性
int rowLen = matrix.length;
int colLen = matrix[0].length;
int i = 0;
int j = colLen - 1;
while(i < rowLen && j >=0){
if(matrix[i][j] < target){
i++;
}else if(matrix[i][j] > target){
j--;
}else{
return true;
}
}
return false;
lt.633-平方数之和
[案例需求]
[思路分析]
[代码实现]
class Solution {
public boolean judgeSquareSum(int c) {
//非负整数, 0,1,2,3,4...
//左右指针法
long L = 0;
long R = (long)Math.sqrt(c);
while(L <= R){
long res = L * L + R * R;
if(res == c){
return true;
}else if(res > c){
R--;
}else if(res < c){
L++;
}
}
return false;
}
}
[思路分析二, 数学法]
[代码示例]
class Solution {
public boolean judgeSquareSum(int c) {
for (int base = 2; base * base <= c; base++) {
// 如果不是因子,枚举下一个
if (c % base != 0) {
continue;
}
// 计算 base 的幂
int exp = 0;
while (c % base == 0) {
c /= base;
exp++;
}
// 根据 Sum of two squares theorem 验证
if (base % 4 == 3 && exp % 2 != 0) {
return false;
}
}
// 例如 11 这样的用例,由于上面的 for 循环里 base * base <= c ,base == 11 的时候不会进入循环体
// 因此在退出循环以后需要再做一次判断
return c % 4 != 3;
}
}
lt.69-Sprt(x)
[案例需求]
[思路分析一, 暴力法]
-
我们可以直接遍历所有可能的值, 用一个for循环, 然后不断的判断某一个i的平方是否能够等于x;
-
当然了, 如果没有一个i 正好能够等于x, 那我们就要寻找这样一个x, 他满足:
- i 的平方 < x , 且, i + 1的平方大于x, 我们直接强制取整返回即可;
-
小小的优化: x的平方根是小于 x / 2的, 所以我们可以让i 从0到 i/ 2进行遍历, 但是0和1是不满足这个条件的, 我们单独进行判断即可;
[代码实现]
class Solution {
public int mySqrt(int x) {
for(long i = 0; i <= x; i++){
if(i * i == x) return (int)i;
if(i * i < x && (i + 1)*(i + 1) > x) return (int)i;
}
return -1;
}
}
class Solution {
public int mySqrt(int x) {
if(x == 1)return 1;
for(long i = 0; i <= x / 2; i++){
if(i * i == x) return (int)i;
if(i * i < x && (i + 1)* (i + 1) > x)return (int)i;
}
return -1;
}
}
[思路分析二, 二分查找法]
[代码示例]
class Solution {
public int mySqrt(int x) {
int left = 0;
int right = x / 2;
while(left <= right){
int mid = left + ((right - left) >> 1);
//二分, 规定右侧是 > x, 左侧是 <= x
if((long)mid * mid <= x){
left = mid + 1;
}else{ // >
right = mid - 1;
}
//等到二分结束之后, right在左区间的边界, 左区间是 <= 结果的, 比如 8的平方根为2
//而left在右区间的边界., 右区间是 > 结果的, 8的平方根会是 3
}
return right;
}
}
[思路分析三, 牛顿迭代法]
- 待补充
- 题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)