[Algoritmo] Dicotomia ② (Encontre o valor alvo na matriz classificada | Escrita clássica da dicotomia | Encontre a última posição do elemento na matriz classificada | Modelo geral da dicotomia )





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;
    }
}

おすすめ

転載: blog.csdn.net/han1202012/article/details/128780169