Diretório de artigos
1. Encontre o valor alvo na matriz classificada (maneira clássica de dicotomia)
https://leetcode.cn/problems/binary-search/
Tópico típico de pesquisa binária: encontre um valor de destino de uma matriz ordenada , retorne o valor de índice do elemento de destino na matriz e retorne -1 se o valor de destino não existir na matriz ;
Por exemplo: procure o valor de destino 2 de [1, 2, 4, 5, 6] e retorne o índice do elemento da matriz correspondente a 2 como 1; se você procurar por 3 na matriz acima e não houver tal elemento na matriz, retorne -1;
Implementação clássica da dicotomia:
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;
}
}
A dicotomia acima é realizada e é possível encontrar o valor alvo na matriz sem nenhum valor repetido;
Caso o valor a ser buscado no array seja repetido, é necessário retornar um índice especificado entre esses valores, como: retornar o último, retornar o primeiro, retornar o enésimo e outros requisitos adicionais, a dicotomia acima isso não pode ser alcançado;
2. Encontre a última posição de um elemento em uma matriz classificada (modelo geral para dicotomia)
Encontre a última posição de um elemento em uma matriz classificada : encontre um valor de destino de uma matriz classificada , retorne o valor do índice do elemento de destino na matriz e os elementos podem ser repetidos,
- Se o valor de destino não existir na matriz , retorne -1;
- Você deve projetar e implementar um algoritmo com complexidade de tempo O(log n) para resolver este problema.
Por exemplo: encontre o valor de destino 2 de [1, 2, 2, 4, 5, 6] e retorne o índice do elemento da matriz correspondente a 2 é 1 e 2, aqui a última posição é pesquisada e o resultado é 2; se da matriz acima Encontre 3 na matriz, se não houver tal elemento na matriz, retorne -1;
O tópico acima requer uma complexidade de tempo de O ( log n ) O(\log n)O ( lo gn ) , no blog anterior[Algorithm] Dicotomia ① (Introdução ao princípio básico da dicotomia | Comparação entre dicotomia e tabela hash | Complexidade de tempo correspondente a algoritmos comuns)mencionou que a complexidade de tempo de algoritmos comuns é a seguinte, tempo A ordem de complexidade de pequeno a grande é:
- O ( 1 ) O(1) O ( 1 ) :operações de bit,pesquisas de tabela de hash
- O ( log n ) O(\log n)O ( lo gn ) :dicotomia,algoritmo de potência rápida,método de rolagem e divisão, método de multiplicação;
- O(n)O(n)O ( n ) :método de enumeração,algoritmo de pilha monótona, algoritmode ponteiro duplo;
- O ( n log n ) O(n \ log n)O ( npouco tempon ) :classificação rápida, classificaçãopor mesclagem, classificaçãopor heap;
- O ( n 2 ) O (n ^ 2)O ( n2 ):método de enumeração, programação dinâmica;
- O (n3) O(n^3)O ( n3 ):método de enumeração, programação dinâmica;
- O (2n) O(2^n)O(2n ):Combinando questões de pesquisa relacionadas;
- O(n!) O(n!)O ( n !) :Problemas de pesquisa relacionados à permutação;
Obviamente, é necessário escolher o método da dicotomia para resolver os problemas do algoritmo acima;
Exemplo 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;
}
}