33. Búsqueda de una matriz ordenada rotada
describir
Los números de la matriz de enteros están ordenados en orden ascendente y los valores de la matriz son diferentes entre sí .
Antes de pasar a la función, nums se rota en un subíndice predesconocido k (0 <= k < nums.length) , de modo que la matriz se convierte en [nums[k], nums[k+1],…, nums[ n-1], nums[0], nums[1],…, nums[k-1]] (los subíndices comienzan a contar desde 0).
Por ejemplo, [0,1,2,4,5,6,7] podría convertirse en [4,5,6,7,0,1,2] después de la rotación en el índice 3.
Proporcione los números de matriz rotados y un objetivo entero; si el valor objetivo existe en nums , devuelva su subíndice ; de lo contrario, devuelva -1 .
Tienes que diseñar un algoritmo con complejidad temporal O (log n) para resolver este problema.
ejemplo
Entrada: números = [4,5,6,7,0,1,2], objetivo = 0
Salida: 4
Entrada: números = [4,5,6,7,0,1,2], objetivo = 3
Salida: -1
respuesta
dicotomía
Para matrices ordenadas, puede utilizar el método de búsqueda binaria para buscar elementos.
Pero en esta pregunta, la matriz en sí no está en orden y solo se garantiza que una parte de la matriz estará en orden después de la rotación.
Cuando dividimos la matriz en partes izquierda y derecha desde el medio, debe haber una parte de la matriz que esté en orden .
Esto sugiere que podemos comprobar qué parte de las dos partes [l, mid] y [mid + 1, r] separadas por el mid actual como posición dividida está en orden durante la búsqueda binaria convencional, y qué parte está en orden según Comparación del tamaño de la parte objetivo para determinar cómo debemos cambiar los límites superior e inferior de la búsqueda binaria, porque podemos juzgar si el objetivo está en esta parte de acuerdo con la parte ordenada:
- Si [l, mid - 1] es una matriz ordenada y el tamaño del objetivo satisface [nums[l], nums[mid]), entonces debemos limitar el rango de búsqueda a [l, mid - 1]; de lo contrario, en [ mid + 1, r] para encontrar.
- Si [mid, r] es una matriz ordenada y el tamaño del objetivo satisface (nums[mid+1], nums[r]], entonces debemos limitar el rango de búsqueda a [mid + 1, r]; de lo contrario, en [ l , mid - 1] para encontrar.
El tamaño de la parte de evaluación en el código La izquierda y la derecha de la parte de evaluación se pueden reemplazar por 0 y n-1, el efecto es el mismo y se utilizan para determinar dónde está la parte ordenada .
- Complejidad del tiempo: O (logn), donde n es el tamaño de la matriz de números. La complejidad temporal de todo el algoritmo es la complejidad temporal O (logn) de la búsqueda binaria.
- Complejidad espacial: O(1) . Sólo necesitamos un nivel constante de espacio para las variables.
class Solution {
public:
int search(vector<int>& nums, int target) {
int n = nums.size();
int left = 0, right = n-1;
while(left <= right){
int mid = (right + left) >> 1;
if(nums[mid] == target) return mid; // 目标索引
if(nums[left] <= nums[mid]){
// 左半边有序,<=
if(target >= nums[left] && target < nums[mid]){
// target 在左半边,mid不是目标索引,因此不需要=判断,下同
right = mid - 1;
}else{
left = mid + 1;
}
}else{
// if(nums[0] > nums[mid]) // 右半边有序
if(target > nums[mid] && target <= nums[right]){
// target 在右半边
left = mid + 1;
}else{
right = mid - 1;
}
}
}
return -1;
}
};
81. Búsqueda de matrices ordenadas rotadas II
describir
Los números de la matriz de enteros están ordenados en orden ascendente y puede haber valores duplicados en la matriz .
Proporcione los números de matriz rotados y un objetivo entero; si el valor objetivo existe en nums , devuelva verdadero ; de lo contrario, devuelva falso .
ejemplo
Entrada: números = [2,5,6,0,0,1,2], objetivo = 0
Salida: verdadero
respuesta
dicotomía
Para el caso en el que hay elementos repetidos en la matriz, puede haber a[l]=a[mid]=a[r] durante la búsqueda binaria. En este momento, es imposible juzgar cuál del intervalo [l, mid ] y el intervalo [mid+1, r] está en orden.
Por ejemplo, nums=[3,1,2,3,3,3,3], target=2, es imposible juzgar si el intervalo [0,3] o el intervalo [4,6] están en orden La primera dicotomía.
En este caso, solo podemos sumar uno al límite izquierdo del intervalo binario actual, restar uno del límite derecho y luego continuar la búsqueda binaria en el nuevo intervalo.
class Solution {
public:
bool search(vector<int>& nums, int target) {
int n = nums.size();
int left = 0, right = n-1;
while(left <= right){
int mid = (left + right) >> 1;
if(nums[mid] == target) return true;
if(nums[left] == nums[mid] && nums[mid] == nums[right]){
// 无法判断有序部分
++left;
--right;
}else if(nums[left] <= nums[mid]){
// 左边有序
if(target >= nums[left] && target < nums[mid]){
// 有序部分判断,target 在左半边
right = mid - 1;
}else{
left = mid + 1;
}
}else{
// 右边有序
if(target > nums[mid] && target <= nums[right]){
// 有序部分判断,target 在右半边
left = mid + 1;
}else{
right = mid - 1;
}
}
}
return false;
}
};
mientras (izquierda <derecha)
#include <vector>
using std::vector;
// 二分寻找
//
// 解题思路:
// 第一类
// 10111和11101这种。此种情况下 "nums[start] == nums[mid]",分不清到底是前面有序还是后面有
// 序,此时! start++即啊。相当于去掉一个重复的干扰项。
// 第二类
// 2345671这种,也就 "是nums[start] < nums[mid]"。此例子中就是2 < 5 ;
// 这种情况下,前半部分有序。因此如果nums[start] <=target<nums [mid],则在前半部分找,否则去后半部分找。
// 第三类
// 6712345这种,也就是nums[start] > nums[mid]。此例子中就是6 > 2 ;
// 这种情况下,后半部分有序。因此如果nums [mid] <target<=nums[end] 。则在后半部分找,否则去前半部分找。
class Solution {
public:
bool search(vector<int>& nums, int target) {
int len = nums.size();
int left = 0, right = len - 1;
while (left < right) {
int mid = left + (right - left) / 2; // mid偏向与左边, 使用left=mid+1,right=mid
// 判断是否找到
if (nums[mid] == target) {
return true;
}
// 是否为第一类情况
if (nums[left] == nums[mid]) {
++left;
continue;
}
// 前半部分有序 (注:只有在有序部分中判断target,才判断出target是在前半部分还是在后半部分!)
if (nums[left] < nums[mid]) {
if (target >= nums[left] && target < nums[mid]) {
right = mid;
}
else {
left = mid + 1;
}
}
// 后半部分有序
else {
if (target > nums[mid] && target <= nums[right]) {
left = mid + 1;
}
else {
right = mid;
}
}
}
return nums[left] == target ? true : false; // 存在因 left==right 而退出循环,从而没有判断nums[mid] == target的情况
}
};