Directorio de artículos
1. Encuentre el valor objetivo en la matriz ordenada (forma clásica de dicotomía)
https://leetcode.cn/problems/binary-search/
Tema típico de búsqueda binaria: encuentre un valor de destino de una matriz ordenada , devuelva el valor de índice del elemento de destino en la matriz y devuelva -1 si el valor de destino no existe en la matriz ;
Por ejemplo: busque el valor objetivo 2 de [1, 2, 4, 5, 6] y devuelva el índice del elemento de matriz correspondiente a 2 como 1; si busca 3 de la matriz anterior y no hay dicho elemento en la matriz, devuelve -1;
Implementación clásica de dicotomía:
public class Solution {
public int search(int[] nums, int target) {
// 1. 判断参数合法性
if(nums == null || nums.length == 0) {
return -1;
}
// 2. 二分查找的范围
int start = 0, end = nums.length - 1;
// 3. 开始循环进行二分查找
while(start <= end) {
// 3.1 计算中间索引
int mid = start + (end - start) / 2;
// 3.2 对比中间元素与目标值
if(nums[mid] == target) {
// 如果 中心元素 = 目标值 , 找到了目标元素 , 直接返回该索引值
return mid;
} else if(nums[mid] > target) {
// 如果 中心元素 > 目标值 , 则需要去 该查找区间的 左侧继续查找
end = mid - 1;
} else {
// 如果 中心元素 < 目标值 , 则需要去 该查找区间的 右侧继续查找
start = mid + 1;
}
}
// 4. 循环完毕 , 说明最终 start > end , 没有找到目标值
return -1;
}
}
La dicotomía anterior se realiza y es posible encontrar el valor objetivo en la matriz sin valor repetido;
Si el valor a buscar en el arreglo se repite, se requiere devolver un índice específico entre estos valores, como: devolver el último, devolver el primero, devolver el enésimo, y otros requisitos adicionales, la dicotomía anterior no se puede lograr;
2. Encuentra la última posición de un elemento en una matriz ordenada (plantilla general para dicotomía)
Encuentre la última posición de un elemento en una matriz ordenada : encuentre un valor objetivo de una matriz ordenada , devuelva el valor de índice del elemento objetivo en la matriz y los elementos se pueden repetir,
- Si el valor de destino no existe en la matriz , devuelve -1;
- Debe diseñar e implementar un algoritmo con complejidad de tiempo O(log n) para resolver este problema.
Por ejemplo: encuentre el valor objetivo 2 de [1, 2, 2, 4, 5, 6] y devuelva el índice del elemento de matriz correspondiente a 2 es 1 y 2, aquí se busca la última posición y el resultado es 2; si de la matriz anterior encuentra 3 en la matriz, si no hay tal elemento en la matriz, entonces devuelve -1;
El tema anterior requiere una complejidad de tiempo de O ( log n ) O(\log n)O ( lo gn ) , en el blog anterior[Algoritmo] Dicotomía ① (Introducción al principio básico de dicotomía | Comparación entre dicotomía y tabla hash | Complejidad de tiempo correspondiente a algoritmos comunes)mencionó que la complejidad de tiempo de algoritmos comunes es la siguiente, tiempo El orden de complejidad de pequeño a grande es:
- O(1) O(1)O ( 1 ) :operaciones de bits,búsquedas en tablas hash
- O ( Iniciar sesión norte ) O(\ Iniciar sesión n)O ( lo gn ) :dicotomía,algoritmo de potencia rápida,método de rodadura y división, método de multiplicación;
- O (n) O (n)O ( n ) :método de enumeración,algoritmo de pila monotono, algoritmo dedoble puntero;
- O ( norte Iniciar sesión norte ) O(n \log norte)O ( niniciar sesiónn ) :clasificación rápida, clasificaciónpor fusión, clasificaciónpor montón;
- O ( norte 2 ) O (n ^ 2)O ( n2 ):método de enumeración, programación dinámica;
- O ( norte 3 ) O (n ^ 3)O ( n3 ):método de enumeración, programación dinámica;
- O (2n) O(2^n)O ( 2n ):Combinación de preguntas de búsqueda relacionadas;
- O (n!) O(n!)O ( n !) :Problemas de búsqueda relacionados con la permutación;
Obviamente, es necesario elegir el método de dicotomía para resolver los problemas de algoritmo anteriores;
Ejemplo de código:
package cn.zkhw.schedule.utils;
public class Solution {
public int search(int[] nums, int target) {
// 1. 判断参数合法性
if(nums == null || nums.length == 0) {
return -1;
}
// 2. 二分查找的范围
int start = 0, end = nums.length - 1;
// 3. 开始循环进行二分查找
// 此处注意 start 和 end 区间需要能覆盖住所有目标值
// 该循环条件很重要 , 是通用模板
// ★ 要点一 : 此处尽量不要使用 start <= end 或 start < end 作为循环判定条件 , 在某些情况下会执行失败
// 为了让程序有更多的适应性 , 这里使用 start + 1 < end 作为循环判定条件 , 可以有效避免死循环
while(start + 1 < end) {
// 3.1 计算中间索引
// ★ 要点二 : 此处尽量不要使用 (start + end) / 2 , 如果 两个数值都接近 Int.MAX_VALUE 则会溢出
int mid = start + (end - start) / 2;
// 3.2 对比中间元素与目标值
if(nums[mid] == target) {
// 如果 中心元素 = 目标值 , 找到了目标元素的第一个位置
end = mid;
} else if(nums[mid] > target) {
// 如果 中心元素 > 目标值 , 则需要去 该查找区间的 左侧继续查找
// ★ 要点三 : 由于循环判定条件是 start + 1 < end , 此处 end 赋值可以不使用 mid - 1
end = mid;
} else {
// 如果 中心元素 < 目标值 , 则需要去 该查找区间的 右侧继续查找
// ★ 要点四 : 由于循环判定条件是 start + 1 < end , 此处 start 赋值可以不使用 mid + 1
start = mid;
}
}
// 4. ★ 要点五 : 循环完毕 , 判定 start 和 end 是不是要找的值
// 如果数组只有两个数的情况下
// while(start + 1 < end) 循环控制条件中的 start + 1 < end 直接为 false
// 循环直接退出 , 此处判定一下 start 和 end 是不是要找的值
if(nums[start] == target) {
return -1;
}
if(nums[end] == target) {
return -1;
}
// 5. 没有找到目标值
return -1;
}
}