704. Búsqueda binaria
Tema Descripción:
Dada una n
matriz entera ordenada (ascendente) de elementos nums
y un valor objetivo target
, escriba una función que nums
devuelva target
el índice si el valor objetivo existe; de lo contrario, devuelva -1
.
Ideas para resolver problemas:
La matriz en esta pregunta está ordenada y bisegmentada, por lo que podemos usar el algoritmo binario para resolver este problema.
Vale la pena señalar que cuando la izquierda y la derecha continúan moviéndose hacia el centro, la izquierda y la derecha pueden apuntar a la misma posición, y esta posición debe juzgarse, por lo que nuestra condición de bucle es izquierda <= derecha
Código de solución:
class Solution {
public:
int search(vector<int>& nums, int target) {
int left=0;
int right=nums.size()-1;
while(left<=right)
{
int mid=left+(right-left)/2;
if(nums[mid]==target) return mid;
if(nums[mid]>target) right=mid-1;
if(nums[mid]<target) left=mid+1;
}
return -1;
}
};
34. Encuentre la primera y última posición del elemento en una matriz ordenada
34. Encuentre la primera y última posición del elemento en una matriz ordenada
Tema Descripción:
Se le proporciona una matriz de números enteros en orden no decreciente nums
y un valor objetivo target
. Encuentre la posición inicial y la posición final del valor objetivo dado en la matriz.
target
Devuelve si el valor objetivo no existe en la matriz [-1, -1]
.
O(log n)
Debe diseñar e implementar un algoritmo con una complejidad temporal de .
Ideas para resolver problemas:
En esta pregunta usamos la bisección para resolver el problema de los extremos izquierdo y derecho. En primer lugar, debe haber izquierda y derecha.
Entendamos esta pregunta a través de un ejemplo: [1,2,3,3,3,4,5]
Encuentre el punto final izquierdo : aquí usamos t en lugar de objetivo (esto es más fácil de describir)
- Operación de pensamiento binario: podemos dividir el ejemplo anterior en dos partes, porque ahora estamos buscando el punto final izquierdo, por lo que puedo dividir el ejemplo en [[1,2], [ 3,3,3,4,5 ] ]
- Cuando x<t, está en el intervalo [1,2], izquierda=mid+1
- Cuando x>=t, está en el intervalo [3,3,3,4,5], derecha=mid (aquí no puede ser igual a mid-1, porque si mid=0, right=-1 saldrá de límites)
- Detalles:
Condición del bucle:
- izquierda<derecha √
- izquierda<=derecha ×
¿Cuál elegimos? Vamos a discutir:
- hay resultados
- Todos son mayores que t (t1), la derecha sigue hacia la izquierda y finalmente la derecha termina con la izquierda. Si izquierda <= derecha, habrá un bucle infinito.
- Todos son menores que t (t2), la izquierda continúa hacia la derecha y finalmente la izquierda termina a la derecha de la derecha.
¡De esto solo podemos elegir la primera opción pero no la segunda!
Encuentre la operación intermedia:
- izquierda+(derecha-izquierda)/2 ×
- izquierda+(derecha-izquierda+1)/2 √
¡Descubrámoslo considerando los casos extremos! Cuando solo quedan dos elementos:
No hay problema con el primer tipo, pero con el segundo tipo mid = 0 + 2/2 = 1. Cuando se realiza la operación izquierda + 1, ocurrirá un evento fuera de límites.
Encuentre el punto final correcto :
- Operación de pensamiento binario: podemos dividir el ejemplo anterior en dos partes, porque ahora estamos buscando el punto final izquierdo, por lo que puedo dividir el ejemplo en [[1,2,3,3,3].[ 4,5 ] ]
- Cuando x<=t, está en el intervalo [1,2,3,3,3], izquierda=media
- Cuando x>t, está en el intervalo [4,5], derecha = mitad-1
- Detalles:
Condición del bucle:
- izquierda<derecha √
- izquierda<=derecha ×
O elige izquierda <derecha
Encuentre la operación intermedia:
- izquierda+(derecha-izquierda)/2 √
- izquierda+(derecha-izquierda+1)/2 ×
¡Descubrámoslo considerando los casos extremos! Cuando solo quedan dos elementos:
En el primer caso, cuando mid=0+1/2=0, right=mid-1 está fuera de límites. En el segundo caso, no hay problema.
Código de solución:
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
//特殊情况处理一下
if(nums.size()==0)return {-1,-1};
int left=0,right=nums.size()-1;
vector<int> ret;
//查找左端点
while(left<right)
{
int mid=left+(right-left)/2;
if(nums[mid]<target)left=mid+1;
if(nums[mid]>=target)right=mid;
}
//当left==right时就是结果
if(nums[left]!=target)return {-1,-1};
else ret.push_back(left);
//查找右端点
left=0,right=nums.size()-1;
while(left<right)
{
int mid=left+(right-left+1)/2;
if(nums[mid]<=target)left=mid;
if(nums[mid]>target)right=mid-1;
}
if(nums[right]!=target)return {-1,-1};
else ret.push_back(right);
return ret;
}
};