Algoritmo: matriz | Notas del campo de entrenamiento juvenil


tema: condensada-noche-púrpura

resaltado: a11y-oscuro

Este es el día 16 de mi participación en la actividad de creación de notas complementarias del "Quinto campo de entrenamiento juvenil".

1. matriz

Una matriz es una colección de datos del mismo tipo almacenados en un espacio de memoria contiguo.

La matriz puede obtener fácilmente los datos correspondientes bajo el subíndice a través del índice de subíndice.

búsqueda binaria

La matriz es una matriz ordenada y no hay elementos repetidos en la matriz, porque una vez que hay elementos repetidos, los subíndices de los elementos devueltos por el método de búsqueda binaria pueden no ser únicos, que son los requisitos previos para usar el método de búsqueda binaria.

Izquierda cerrada derecha cerrada [izquierda, derecha] * * **

  • while (izquierda <= derecha) * * Para usar <=, porque izquierda == derecha tiene sentido, así que use <=
  • si (nums[medio] > destino) * a la derecha se le debe asignar el medio - 1*, porque los números actuales [medio] no deben ser el destino, entonces la posición del subíndice final del intervalo izquierdo que se buscará a continuación es medio - 1

Izquierda cerrada derecha abierta [izquierda, derecha) * *

  • while (izquierda < derecha) , use < aquí, porque izquierda == derecha no tiene sentido en el intervalo [izquierda, derecha)
  • si (nums[middle] > target) right se actualiza a middle , porque los nums[middle] actuales no son iguales al target, vaya al intervalo izquierdo para continuar la búsqueda, y el intervalo de búsqueda es un intervalo cerrado por la izquierda y abierto por la derecha , por lo que la derecha se actualiza al medio, es decir: el siguiente El intervalo de consulta no comparará números [medio]

izquierda + ((derecha -izquierda) >> 1) == (izquierda + derecha) /2

>>: desplazamiento binario a la derecha

Por ejemplo: 1010 >> 1 == 0101

1010 decimal 10

0101 decimal 5

En resumen >> 1 equivale a dividir entre dos

所以 izquierda + ((derecha -izquierda) >> 1) ==> izquierda + ((derecha -izquierda)/2)

==> izquierda + derecha/2 -izquierda/2 ==> izquierda/2 + derecha/2 ==> (izquierda + derecha) /2

Pregunta: ¿por qué no usar simplemente (izquierda + derecha) /2 sino usar izquierda + ((derecha -izquierda) >> 1)

Respuesta: Porque izquierda + derecha pueden exceder el valor máximo que el tipo básico puede contener en algunos casos, y >> (operación de bits) es más rápida que la operación /

Encuentre la primera y última posición de un elemento en una matriz ordenada

https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/submissions/

Ideas para resolver problemas:

Encuentre los límites izquierdo y derecho, si hay un objetivo en la matriz, en el subíndice 3, los límites izquierdo y derecho son [4, 5]

Encuentre el límite: el objetivo se registra justo a la izquierda y irá más hacia la izquierda

El objetivo se registra a la izquierda a la derecha y irá más a la derecha.

Al regresar,

  • 只要有一个边界为-2, target 在数组范围的右边或者左边,例如数组{3, 4, 5},target为2或者数组{3, 4, 5},target为6,此时应该返回{-1, -1} if(leftBorder === -2 || rightBorder === -2 )
  • target 在数组范围中,且数组中存在target,例如数组{3,6,7},target为6,此时应该返回{1, 1}

if (rightBorder - leftBorder > 1)         return [leftBorder + 1, rightBorder - 1]

  • target 在数组范围中,且数组中不存在target,例如数组{3,6,7},target为5,此时应该返回{-1, -1} return [-1, -1]

移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

暴力解法

这个题目暴力的解法就是两层for循环,一个for循环遍历数组元素 ,第二个for循环更新数组。

双指针法

双指针法(快慢指针法)通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。

定义快慢指针

  • 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
  • 慢指针:指向更新 新数组下标的位置

注意这些实现方法并没有改变元素的相对位置

int slowIndex = 0; for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) { if (val != nums[fastIndex]) { nums[slowIndex++] = nums[fastIndex]; } } return slowIndex;

题目:外面有宝,赶紧捡回来按序放好,不能重样哟 有点像小夫妻俩,老公q在外面淘宝,找到后运回来,找到一个新的宝,老婆p在家里就给挖个新坑放好,最后外面没宝了,就结束咯

中间对话

老公:老婆,这个家里有没?(if) 老婆:有了。(nums[p] == nums[q])你再找找(q++)

老公:老婆,这个家里有没?(if) 老婆:有了。(nums[p] == nums[q])你再找找(q++)

老公:老婆,这个家里有没?(if) 老婆:这个没有,拿回来吧 (nums[p] != nums[q]) 放好了,我到下一个位置等你(p++) 你再继续找吧(q++)

貌似双指针都可以这么理解

相向双指针方法,基于元素顺序可以改变的题目描述改变了元素相对位置,确保了移动最少元素

int leftIndex = 0; int rightIndex = nums.size() - 1; while (leftIndex <= rightIndex) { // 找左边等于val的元素 while (leftIndex <= rightIndex && nums[leftIndex] != val){ ++leftIndex; } // 找右边不等于val的元素 while (leftIndex <= rightIndex && nums[rightIndex] == val) { -- rightIndex; } // 将右边不等于val的元素覆盖左边等于val的元素 if (leftIndex < rightIndex) { nums[leftIndex++] = nums[rightIndex--]; } } return leftIndex; // leftIndex一定指向了最终数组末尾的下一个元素

https://www.programmercarl.com/0027.%E7%A7%BB%E9%99%A4%E5%85%83%E7%B4%A0.html#%E6%80%9D%E8%B7%AF

题目

双指针法,i指向起始位置,j指向终止位置。

定义一个新数组result,和A数组一样的大小,让k指向result数组终止位置。

如果A[i] * A[i] < A[j] * A[j] 那么result[k--] = A[j] * A[j]; 。

如果A[i] * A[i] >= A[j] * A[j] 那么result[k--] = A[i] * A[i]; 。

滑动窗口

滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果

在暴力解法中,是一个for循环滑动窗口的起始位置,一个for循环为滑动窗口的终止位置,用两个for循环 完成了一个不断搜索区间的过程。

那么滑动窗口如何用一个for循环来完成这个操作呢。

如果用一个for循环,那么应该表示 滑动窗口的起始位置,还是终止位置。

  • 如果只用一个for循环来表示 滑动窗口的起始位置,遍历剩下的终止位置难免再次陷入 暴力解法的怪圈。
  • 所以 只用一个for循环,那么这个循环的索引,一定是表示 滑动窗口的终止位置

实现滑动窗口,主要确定如下三点:

  • 窗口内是什么?
  • 如何移动窗口的起始位置?
  • 如何移动窗口的结束位置?

题目:长度最小的子数组

在本题中

  • 窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。
  • 窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)。
  • 窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。

滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)暴力解法降为O(n)。

var minSubArrayLen = function(target, nums) {     let sum = 0,         result = nums.length ,         j = 0,         i = 0,         subL = 0;     for (; j < nums.length; j ++) {         sum += nums[j]         while (sum >= target) {             subL = j - i + 1;             result = result < subL ? result : subL;             sum -= nums[i ++];         }     }     return result };

题目

/**  * @param {number[]} fruits  * @return {number}  */ var totalFruit = function(fruits) {     let l = 0;//起始指针     let maxLen = 0;//窗口的最大长度 其中最多包涵两种水果     let n = 0//前一类水果的结束位置     let arr = [fruits[l]]//水果的种类数组     console.log(arr)     for(let r = 0; r < fruits.length; r++){//窗口的右指针不断前进         if(!arr.includes(fruits[r])){//如果窗口中不包含 进窗口的水果             if(arr.length <= 1){//如果只有一种水果                 arr[1] = fruits[r]//将这种水果加入arr数组             }else{//如果有两种水果                 l = n//更新窗口的左边界                 arr[0] = fruits[r-1]//更新arr中水果的种类                 arr[1] = fruits[r]             }         }                 if(fruits[r] !== fruits[n]){//如果进来了一种新的类型的水果 更新前一种水果的位置             n = r         }         maxLen = Math.max(maxLen,r-l+1)//更新滑动窗口的最大值     }     return maxLen };

螺旋矩阵https://leetcode.cn/problems/spiral-matrix-ii/submissions/

给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。

坚持循环不变量原则

模拟顺时针画矩阵的过程:

  • 填充上行从左到右
  • 填充右列从上到下
  • 填充下行从右到左
  • 填充左列从下到上

由外向内一圈一圈这么画下去

每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来

math函数库中的一个函数,math.floor (x) 返回小于参数x的最大整数,即对浮点数向下取整。x[]的取值。

Array.fill

arr.fill(value[, start[, end]])

fill() 方法用一个固定值填充一个数组中,

从起始索引到终止索引内的全部元素,

不包括终止索引,

返回被修改后的数组。

value:用来填充数组元素的值。

start:起始索引,默认值为0。

end:终止索引,默认值为 this.length。

``` /**  * @param {number} n  * @return {number[][]}  */ var generateMatrix = function(n) {     let loop = Math.floor(n / 2);     let mid = Math.floor(n / 2);     let count = 1     let row = col = 0     let startX = startY = 0     let offset = 1     let res = new Array(n).fill(0).map(() => new Array(n).fill(0));

    while(loop --) {         row = startX         col = startY         for(; col < n - offset ; col ++)              res[row][col] = count ++

        for (; row < n - offset ; row ++)             res[row][col] = count ++

        for (; col > startY; col --)             res[row][col] = count ++

        for (; row > startX; row --)             res[row][col] = count ++                  startX ++         startY ++         offset += 1     }     if(n % 2 === 1)         res[mid][mid] = count           return res }; ```


题目: 给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。 https://leetcode.cn/problems/spiral-matrix/


Supongo que te gusta

Origin blog.csdn.net/weixin_50945128/article/details/129377822
Recomendado
Clasificación