1. Escenario de uso:
Generalmente, cuando es necesario obtener un segmento determinado de los elementos de la matriz, los punteros rápidos y lentos se pueden paralelizar.
El método de doble puntero (método de puntero rápido y lento) es muy común en la operación de matrices y listas enlazadas.Muchas preguntas de entrevista que investigan operaciones en matrices, listas enlazadas y cadenas utilizan el método de doble puntero.
2. Tipo:
Punteros rápidos y lentos, punteros de cabeza y cola, ventanas deslizantes, etc.
3. Cómo usar
(1) La j en el bucle for es equivalente a un puntero
Luego puede definir una variable global i como otro puntero y usar i++ para mover el puntero para
let i = 0
for (let j = 0; j < arr.length; j++){
arr[i++] = arr[j]
}
(2) A veces, dos punteros se definen directamente en el bucle for
for (let i = 1, j = 0; arr[i] < arr[j]){
}
4. Escenarios de aplicación
(1) Eliminar elementos de la matriz
Dada una matriz nums y un valor val, debe eliminar todos los elementos cuyo valor sea igual a val en su lugar y devolver la nueva longitud de la matriz eliminada.
No use espacio de matriz adicional, debe usar solo O (1) espacio adicional y modificar la matriz de entrada en el lugar .
El orden de los elementos se puede cambiar. No necesita considerar elementos en la matriz más allá de la nueva longitud.
Idea: puntero rápido para encontrar los elementos de la nueva matriz (elementos que no son iguales a val)
El puntero lento identifica dónde la nueva matriz es actualmente capaz de agregar nuevos elementos (en realidad, sobrescribe elementos de la matriz anterior)
// 时间复杂度:O(n)
// 空间复杂度:O(1)
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slowIndex = 0;
for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) { //一开始两个指针都指向一个元素
if (val != nums[fastIndex]) { //一旦等于,快指针就把慢指针甩开了
nums[slowIndex++] = nums[fastIndex]; //一开始相当于自己给自己赋值
//一旦甩开了就是后一个给前一个赋值
}
}
return slowIndex;
}
};
(2) El cuadrado de un arreglo ordenado (arreglos en orden no decreciente, positivo y negativo)
Dada una matriz de números enteros ordenados en orden no decreciente, devuelve una nueva matriz que consiste en el cuadrado de cada número, también ordenados en orden no decreciente.
Idea: un puntero de cabeza, un puntero de cola
Compare los valores cuadrados de los elementos actualmente señalados por los dos y póngalos en el conjunto de resultados
class Solution {
public:
vector<int> sortedSquares(vector<int>& A) {
int k = A.size() - 1; //指向新数组,从尾部开始移动
vector<int> result(A.size(), 0); //新数组
for (int i = 0, j = A.size() - 1; i <= j;) { // 注意这里要i <= j,因为最后要处理两个元素
if (A[i] * A[i] < A[j] * A[j]) {
result[k--] = A[j] * A[j];
j--;
}
else {
result[k--] = A[i] * A[i];
i++;
}
}
return result;
}
};
(3) El subarreglo con la longitud más pequeña
Dada una matriz que contiene n enteros positivos y un entero positivo s, encuentre el subarreglo continuo más pequeño cuya suma ≥ s en la matriz y devuelva su longitud. Devuelve 0 si no existe ningún subarreglo coincidente.
Idea: ¡La ventana deslizante también puede entenderse como una especie de método de doble puntero!
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
int result = INT32_MAX;
int sum = 0; // 滑动窗口数值之和
int i = 0; // 滑动窗口起始位置
int subLength = 0; // 滑动窗口的长度
for (int j = 0; j < nums.size(); j++) {
sum += nums[j];
// 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件
while (sum >= s) { //一旦和超过了目标值
subLength = (j - i + 1); // 取子序列的长度
result = result < subLength ? result : subLength; //如果出现了更短的,就把结果改成更短的
sum -= nums[i++]; // 移除第一个元素。这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
}
}
// 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
return result == INT32_MAX ? 0 : result;
}
};