Série recursiva de estrutura de dados e algoritmo

Série recursiva de estrutura de dados e algoritmo

Escreva na frente

Há alguns meses, queria escrever um artigo assim para compartilhar com todos, porque tenho coração e falta de energia, não consegui estabelecer o que aprendi, então tenho aprendido constantemente por mim mesmo.

Depois, demorou mais uma semana para classificar e categorizar, e então eu tenho este compartilhamento de 8.000 palavras sobre recursão. Espero que possa ajudar amigos que estão aprendendo recursão. Este artigo é uma versão reduzida. Você pode clicar em "Ler o texto original" para veja a versão completa.

E com o apoio e motivação deste artigo, vou escrever alguns conceitos difíceis sobre estruturas de dados e algoritmos para simplificar. Se houver erros no artigo, espero que você possa me corrigir e compartilhar mais artigos de qualidade para outras pessoas!

O próximo artigo que irei compartilhar é sobre recursão. Este artigo não compartilha apenas sobre recursão. Acho que é mais importante transmitir uma reflexão a cada leitor. pensamento? Sim está certo! Não se pode dizer que este artigo inclui os cantos e cantos da recursão, mas por meio de meu próprio estudo teórico e prática, tenho meu próprio conjunto de ideias recursivas.

Quais problemas devem ser recursivos, quais problemas devem ser concisos com recursão, quais problemas não podem ser resolvidos por recursão e a armadilha de usar recursão para resolver problemas específicos, podemos otimizar ainda mais a recursão, esses são os conteúdos compartilhados por Xiaolu hoje.

O que é recursão

A recursão, como o nome indica, é chamada de recursão se houver recursão, se houver recursão, ou se houver recursão sem recursão, é chamada de "jogar um trapaceiro".

Por que aprender recursão

Quer aprendamos uma tecnologia ou uma linguagem de programação, antes de aprendê-la, sabemos o que ela pode nos trazer e que tipo de problemas pode nos ajudar a resolver. É isso que nos motiva a aprendê-la.

De arrays a listas vinculadas, tabelas hash, algoritmos básicos, etc., até depois da recursão, parece muito difícil de entender. Acredito que todos se sintam assim.Foi muito difícil no início, mas depois de passar por noventa e nove e oitenta e um problemas, eu ainda não entendia os truques da recursão e então pulei naturalmente.

Mais tarde, comecei a estudar as questões do LeetCode por um mês e descobri que a recursão tem um lugar nas estruturas de dados e algoritmos, governando o país. A maioria das questões pode ser resolvida por recursão, como: travessia de árvore binária, algoritmo de retrocesso, problema de mochila 0-1, travessia de profundidade primeiro, algoritmo de retrocesso, etc. Classifiquei pelo menos 20 a 30 questões sobre recursão e encontrei out A importância da recursão, então eu tenho que reaprender recursivamente, tudo com o artigo de hoje.

Como entender a recursão

Minha definição do tipo "invasor" recursivo acima não permite que você entenda exatamente o que é recursão, então vamos dar um exemplo ao vivo.

1. Problema

Por exemplo, você, como Xiaolu e eu, gosta de entrar na fila para o jantar na faculdade (como um aluno três-bom, como posso fazer esse tipo de coisa? Haha), então os colegas atrás da equipe contaram que havia 5 colegas na frente deles, então era a vez deles Agora, porque os colegas da frente continuavam pulando na fila, ele descobriu neste momento, como ele se sentia ao se distanciar cada vez mais da janela de cozinhar? Neste momento, se ele quiser saber seu número na fila (desde que ninguém pule na fila) e resolvê-lo com pensamento recursivo, o que devemos fazer?

2. "Passe"

Então ele perguntou qual colega da frente estava, e os colegas da frente não estavam apenas lá, então o colega da frente perguntou quem estava na frente dele, até que o segundo colega da frente perguntou quem era o primeiro colega que estava cozinhando O número um da equipe (um pouco embaraçoso). O colega que estava cozinhando disse impaciente, você não viu que eu era o primeiro a cozinhar? Este processo é na verdade um processo de "passagem" na recursão.

3. "Devolução"

Então o segundo colega que estava cozinhando na frente, impaciente, disse ao terceiro que eu era o segundo.Não vi um cara na minha frente que estava cozinhando? Em seguida, a terceira é passada para a quarta e, mais tarde, até que a pessoa na frente do colega que está se afastando gradativamente da janela lhe diga em que posição está, ela saberá sua posição atual na equipe. Esse processo pode ser entendido como o processo de "recursão" em recursão.

4. Condições de rescisão

“O colega que janta disse impaciente, você não viu que eu fui o primeiro a jantar?” Em recursão, chamamos isso de condição de rescisão.

5. Como entender a recursão

Embora o problema seja a análise recursiva, quando expressa em programas, não chame o código recursivo no cérebro camada por camada para pensar sobre isso. Isso pode fazer você cair completamente no processo de "recursivo"., Não posso voltar atrás, essas são coisas que deixamos para o computador fazer.

Então, como entendemos a recursão ao escrever programas? Procuramos apenas a relação entre os problemas, protegendo os detalhes da recursão, consulte (5) análise para obter detalhes.

Satisfaça a condição recursiva

Que tipo de problemas podem ser resolvidos por recursão? Quais são as características e existem condições de julgamento?

1. Um problema pode ser resolvido em vários subproblemas?

Quer saber onde você está na equipe e dividir o problema em várias subquestões, como "onde estão todos na equipe".

2. O problema é igual ao subproblema?

Se você quiser saber sua localização atual, terá que perguntar onde está a pessoa da frente. Se a pessoa à frente quiser saber onde está, deve saber a localização da pessoa à sua frente. Portanto, a solução do problema e o subproblema são iguais e satisfazem a segunda condição.

3. Existe alguma condição de rescisão para o problema?

O primeiro aluno a cozinhar diz que é a primeira pessoa da equipa. Esta é a chamada condição de rescisão. Depois de encontrada a condição de rescisão, inicia-se o processo de "devolução".

Classificação recursiva

Fazendo muitas perguntas, resolvendo diferentes problemas de acordo com a recursão, várias maneiras de resolver e pensar são derivadas. A razão para categorizá-lo é para entender melhor o papel da recursão em diferentes problemas, tais como: a relação entre cada camada de recursão, cálculo e enumeração recursiva de todas as situações e recursão enfrentando problemas de seletividade. Embora dividido em várias categorias, a natureza da recursão é imutável.

※ Categoria 1: tipo de cálculo recursivo

1. Cálculo de camada por camada

Computação camada por camada, como o nome sugere, os problemas que podem ser resolvidos por recursão podem ser divididos em vários subproblemas. Podemos abstrair cada subproblema em uma camada, e a relação entre os subproblemas pode ser expressa como a relação entre as camadas. Usamos a fórmula recursiva para expressar o cálculo por meio da relação de cálculo entre as camadas e, por fim, obter o valor do resultado após as camadas de recursão.

▉ Exemplo:

Vejamos o exemplo da fila para jantar acima para ilustrar que nosso subproblema foi analisado, ou seja, quero saber a posição atual da equipe, que é me perguntar onde está a pessoa da frente mais um é o meu posição da equipe atual, isso como uma camada. A pessoa na frente deseja saber sua posição atual e precisa usar a mesma solução que outra camada.

Qual é a relação entre as camadas (qual é a relação entre minha posição atual na equipe e a posição da pessoa à minha frente)? Neste momento, você dirá que atualmente é +1. Isso é fácil para a maioria das pessoas descobrir. Agora que o relacionamento está determinado, é fácil escrever código recursivo por meio da fórmula recursiva.


1// f(n) 为我所在的当前层
2// f(n-1) 为我前边的人所在的当前层
3// + 1 是层与层之间的计算关系
4f(n) = f(n-1) + 1

▉ Resumo:

Chamei o tipo de problema recursivo acima de "tipo de cálculo recursivo" "tipo de cálculo em camadas".

▉ Aprendam uns com os outros:

O problema de buscar idade também é um problema do tipo de cálculo em camadas, tente analisá-lo por si mesmo (você deve tentar pensar sobre isso você mesmo e codificar manualmente para entender melhor as habilidades recursivas).

Questão 1: Há 5 pessoas sentadas juntas e perguntado quantos anos a 5ª pessoa tem. Ele disse que é 2 anos mais velho que a 4ª pessoa. Questionado sobre a idade da quarta pessoa, ele disse que era 2 anos mais velho do que a terceira pessoa. Quando questionado sobre a idade da terceira pessoa, ele disse que era 2 anos mais velho que a segunda pessoa. Quando questionado sobre a idade da segunda pessoa, ele disse que era 2 anos mais velho que a primeira pessoa. Por fim, perguntei à primeira pessoa e ela disse que tinha 10 anos. Escreva um programa para descobrir a idade correspondente ao inserir o número de pessoas.

Problema dois : a lista vinculada isoladamente emite o valor do nó do final até a primeira vez, o que é realizado por recursão.

2. Cálculo paralelo

Cálculo paralelo, como o nome indica, a solução para o problema é obter o resultado por meio do cálculo paralelo recursivo. Não há uma relação de cálculo certa entre as camadas, mas simplesmente altere os valores dos parâmetros de entrada.

▉ Exemplo:

O tipo de pergunta mais clássico é a sequência de Fibonacci. Observe tal conjunto de dados 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ..., exceto para o primeiro e segundo dados, o resto dos dados é igual à soma do primeiro dois dados (por exemplo: 2 = 1 + 1, 8 = 3 + 5, 34 = 21 + 13). Você pode tentar analisá-lo de acordo com as etapas de "satisfazer as três condições de recursão" e "como escrever código recursivo".

Eu também faço uma pequena análise aqui.

1) A primeira etapa: primeiro determine se o problema pode ser dividido em vários subproblemas. Eu o analisei acima. Exceto para o primeiro e o segundo dados, os outros dados são a soma dos dois primeiros dados. Então, como você sabe os dois primeiros dados? A mesma solução é a soma dos dois primeiros números.

2) A segunda etapa: Encontre a condição de terminação, se continuar a encontrar a soma dos dois primeiros números, até os três primeiros dados 0, 1, 1. Se o primeiro 1 for encontrado recursivamente, os dados anteriores não são suficientes, portanto, esta também é a condição de término que encontramos.

3) A terceira etapa: Agora que encontramos as condições e relações de terminação, não é difícil escrever a fórmula de recorrência f (n) = f (n-1) + f (n-2) (n é o número necessário Valor numérico).

4) Convertido em código recursivo da seguinte forma:


1function f(n) {
2    // 终止条件
3    if(n == 0) return 0;
4    if(n == 1) return 1;
5    // 递推公式
6    return f(n-1) + f(n-2);
7}

▉ Resumo:

Eu resumi a pergunta acima como um tipo de cálculo paralelo. Também pode ser classificado como um tipo de cálculo em camadas, mas + 1 é alterado para adicionar uma recursão da própria função f (para ser franco, o resultado da recursão também é um valor exato).

Os chamados cálculos paralelos f (n-1) ef (n-2) não perturbam um ao outro e calculam seus respectivos valores recursivamente. Finalmente, adicionamos o valor do resultado calculado é o resultado que mais queremos.

▉ Aprendam uns com os outros:

Pergunta: Um sapo pode saltar até 1 ou 2 passos de cada vez. Encontre o número total de métodos de salto que o sapo pula em uma etapa de nível n.

※ Categoria 2: tipo de enumeração recursiva

A aplicação mais comum da enumeração recursiva é o algoritmo de backtracking, que enumera todas as situações possíveis.Como enumerar todas as situações? Enumere por meio de técnicas de programação recursivas. Então, qual é o algoritmo de retrocesso? Por exemplo, caminhando pelo labirinto, caminhando da entrada até a saída, se você encontrar um beco sem saída, você precisa voltar, voltar ao cruzamento anterior e pegar outra bifurcação. Repita o método acima até encontrar a saída .

Os problemas mais clássicos de algoritmos de retrocesso são a travessia em primeiro lugar, o problema das oito rainhas, etc., que são amplamente usados. A seguir, o problema das oito rainhas como um exemplo de análise. Outros algoritmos de retrocesso que usam enumeração recursiva são muito simples.

Problema das Oito Rainhas

Na grade de 8 X 8, coloque oito rainhas (peças de xadrez), e a condição é que duas rainhas (peças de xadrez) não possam estar na mesma linha, coluna ou linha diagonal. Pergunte quantos tipos de colocações existem no caminho ?

Série recursiva de estrutura de dados e algoritmo
Figura (1) Situação correta

Série recursiva de estrutura de dados e algoritmo
Figura (2) Situação de erro

▉ Análise do problema:

Se você quiser garantir que quaisquer duas rainhas (damas) não podem estar na mesma linha, mesma coluna ou na mesma barra, você precisa enumerar todas as colocações das rainhas (damas) uma por uma e, em seguida, definir as condições para filtrar as condições que atendem às condições.


▉ Ideia do algoritmo:

Depois de analisarmos o problema claramente, como podemos implementar um algoritmo de retrocesso recursivo para enumerar todas as ocorrências das oito rainhas (peças de xadrez)?

1) Na grade 8 x 8, colocamos primeiro a primeira rainha (peão) na primeira coluna da primeira linha (ou seja, coordenadas: (0,0)).

2) Então colocamos a segunda rainha (peão) na segunda linha, colocamos na primeira coluna, e então julgamos se há outra rainha na mesma linha, coluna e barra? Se existir, a posição é inadequada e, em seguida, coloque-a na próxima coluna e, em seguida, julgue se atende às condições que estabelecemos.

3) Depois que a segunda rainha (peão) encontrar uma posição adequada, coloque o terceiro peão na terceira linha e coloque as oito rainhas na posição apropriada por vez.

4) Essa é apenas uma possibilidade, pois a primeira rainha que eu configurei é uma posição fixa, na posição (0,0) das coordenadas da grade, então como enumerar todos os casos? Então mudamos constantemente a posição da primeira rainha, a posição da segunda rainha ..., podemos enumerar todas as situações. Se você é como eu, depois de ler esta pergunta, se você ainda é um pouco ignorante, analise o código diretamente.

▉ Implementação do código:

Embora o código seja implementado em javascript, acredito que a lógica básica do código de amigos que aprenderam programação podem entender. De acordo com as três condições satisfeitas pela análise recursiva resumida acima e as etapas de como escrever código recursivo, analise o problema das oito rainhas passo a passo.

1. Decompor o problema em vários subproblemas

Na análise de código acima e na análise de pensamento de algoritmo, podemos saber aproximadamente como decompor o problema. Enumerar todas as situações de satisfação das oito rainhas (peças de xadrez) pode ser decomposto no subproblema de encontrar cada situação de satisfação primeiro. Por exemplo, a ideia do algoritmo de cada subproblema são as quatro etapas listadas acima.

2. Descubra as condições de rescisão

Quando a oitava linha é alcançada, a recursão termina.


1// 终止条件
2if(row === 8){
3    // 打印第 n 种满足的情况
4    console.log(result)
5    n++;
6    return;
7}

3. Escreva a fórmula de recorrência

A função isOkCulomn () julga se a posição encontrada satisfaz as condições (não pode estar na mesma linha, coluna ou barra). Se as condições forem atendidas, retornamos true, entramos no julgamento if e o número de linhas mais um é passado para recursar a posição rainha da próxima linha. Até que a recursão encontre a posição de condição de terminação, coluna ++, coloque a rainha na primeira linha para a próxima posição, continue a recursão e enumere todas as situações de colocação possíveis.


 1// 每一列的判断
 2for(let column = 0; column < 8; column++){
 3    // 判断当前的列位置是否合适
 4    if(isOkCulomn(row,column)){
 5        // 保存皇后的位置
 6        result[row] = column;
 7        // 对下一行寻找数据
 8        cal8queens(row + 1);
 9    }
10    // 此循环结束后,继续遍历下一种情况,就会形成一种枚举所有可能性
11}

 1// 判断当前列是否合适
 2const isOkCulomn = (row,column) =>{
 3    // 左上角列的位置
 4    let leftcolumn = column - 1;
 5    // 右上角列的位置
 6    let rightcolumn = column + 1;
 7
 8    for(let i = row - 1;i >= 0; i--){
 9        // 判断当前格子正上方是否有重复
10        if(result[i] === column) return false;
11
12        // 判断当前格子左上角是否有重复
13        if(leftcolumn >= 0){
14            if(result[i] === leftcolumn) return false;
15        }
16
17        // 判断当前格式右上角是否有重复
18        if(leftcolumn < 8){
19            if(result[i] === rightcolumn) return false;
20        }
21
22        // 继续遍历
23        leftcolumn --;
24        rightcolumn ++;
25    }
26    return true;
27}

4. Converta para código recursivo


 1// 变量
 2// result 为数组,下标为行,数组中存储的是每一行中皇后的存储的列的位置。
 3// row 行  
 4// column 列
 5// n 计数满足条件的多少种
 6var result = [];
 7let n = 0
 8const cal8queens = (row) =>{
 9    // 终止条件
10    if(row === 8){
11        console.log(result)
12        n++;
13        return;
14    }
15    // 每一列的判断
16    for(let column = 0; column < 8; column++){
17        // 判断当前的列位置是否合适
18        if(isOkCulomn(row,column)){
19            // 保存皇后的位置
20            result[row] = column;
21            // 对下一行寻找数据
22            cal8queens(row + 1);
23        }
24        // 此循环结束后,继续遍历下一种情况,就会形成一种枚举所有可能性
25    }
26}
27
28// 判断当前列是否合适
29const isOkCulomn = (row,column) =>{
30    // 设置左上角
31    let leftcolumn = column - 1;
32    let rightcolumn = column + 1;
33
34    for(let i = row - 1;i >= 0; i--){
35        // 判断当前格子正上方是否有重复
36        if(result[i] === column) return false;
37
38        // 判断当前格子左上角是否有重复
39        if(leftcolumn >= 0){
40            if(result[i] === leftcolumn) return false;
41        }
42
43        // 判断当前格式右上角是否有重复
44        if(leftcolumn < 8){
45            if(result[i] === rightcolumn) return false;
46        }
47
48        // 继续遍历
49        leftcolumn --;
50        rightcolumn ++;
51    }
52    return true;
53}
54
55// 递归打印所有情况
56const print = (result)=>{
57    for(let i = 0;i < 8; i++){
58        for(let j = 0;j < 8; j++){
59            if(result[i] === j){
60                console.log('Q' + ' ')
61            }else{
62                console.log('*' + ' ')
63            }
64        }
65    }
66}
67
68// 测试
69cal8queens(0);
70console.log(n)

▉ Resumo

O problema das oito rainhas mencionadas acima é usar a recursão para enumerar todas as situações e, em seguida, definir as condições a partir delas e apenas filtrar as opções que atendem às condições. É recomendável ler o código acima várias vezes e praticar você mesmo. No começo, resolvi o problema das oito rainhas, observei por muito tempo para entender e como a recursão desempenhava um papel complicado.

▉ Aprendam uns com os outros:

Se quiser praticar suas mãos, você mesmo pode implementar a travessia em profundidade na figura a seguir. Isso não é difícil de entender. Você pode tentar escrevê-lo sozinho. Fiz upload do código para meu Github.

※ Categoria 3: tipo de seleção recursiva

No chamado tipo de seleção recursiva, cada subproblema deve enfrentar uma escolha e buscar a solução ótima. Alguns amigos dirão que a programação dinâmica para a solução ótima é a mais adequada, sim, sim, mas enumerar recursivamente todos os casos por meio de seleção, definir as condições e encontrar a solução ideal para o problema também pode ser alcançada, então, e eu Esse tipo de problema é classificado como um problema de seleção recursiva.

0 -1 problema de mochila

O problema da mochila 0-1 é familiar aos amigos que o conheceram. Na verdade, esse problema também pertence a uma espécie de algoritmo de retrocesso, não muito absurdo, diretamente no problema. Há uma mochila, o peso total da mochila é Wkg. Agora temos n itens, cada um deles com pesos diferentes e indivisíveis. Esperamos agora selecionar alguns itens e carregá-los na mochila. Como maximizar o peso total dos itens da mochila sem exceder o peso da mochila?

▉ Análise do problema:

Se você está confuso sobre esse assunto, não importa, vamos analisar um pouco. Se temos dois estados para cada item, existem 2 ^ n tipos de métodos de instalação total. Como não repetir essas possibilidades?

▉ Ideia do algoritmo:

Podemos organizar os itens em ordem, e todo o problema é dividido em n etapas, e cada etapa corresponde a como escolher um item. Primeiro processe o primeiro item, escolha carregá-lo ou não e, em seguida, processe os itens restantes recursivamente.

▉ Implementação do código:


 1// 用来存储背包中承受的最大重量
 2var max = Number.MIN_VALUE;
 3// i: 对第 i 个物品做出选择
 4// currentw: 当前背包的总重量
 5// goods:数组,存储每个物品的质量
 6// n: 物品的数量
 7// weight: 背包应承受的重量
 8const f = (i, currentw, goods, n, weight) => {
 9    // 终止条件
10    if(currentw === weight || i === n){
11        if(currentw > max){
12            // 保存满足条件的最大值
13            max = currentw;
14        }
15        return ;
16    }
17
18    // 选择跳过当前物品不装入背包
19    f(i+1, currentw, goods, n, weight)
20
21    // 将当前物品装入背包
22    // 判断当前物品装入背包之前是否超过背包的重量,如果已经超过当前背包重量,就不要就继续装了
23    if(currentw + goods[i] <= weight){
24        f(i+1 ,currentw + goods[i], goods, n, weight)
25    }
26}
27
28let a = [2,2,4,6,3]
29f(0,0,a,5,10)
30console.log(max)

Desvantagens da recursão

Embora o uso de recursão seja muito conciso, ele também tem muitas deficiências e é também onde precisamos de atenção extra e otimização no uso.

1. Estouro de pilha recursiva

▉ Entenda o estouro da pilha

1) A essência da recursão é o processo de chamar a si mesmo repetidamente. Claro que é uma função. Bem, existem parâmetros e algumas variáveis ​​declaradas localmente na função. Eu acredito que muitos amigos só usam a função e não sabem como as variáveis ​​na função são armazenadas. Não importa, quando você ouvir minha análise, você estará lá.

2) As variáveis ​​da função são armazenadas na pilha do sistema.A estrutura de dados da pilha é caracterizada por primeiro a entrar, último a sair e último a entrar, primeiro a sair. O uso de variáveis ​​em uma função muda com o ciclo de vida da função. Quando executamos uma função, as variáveis ​​da função continuam a ser colocadas na pilha. Quando a função é executada e destruída, os elementos na pilha são retirados da pilha por sua vez. Ainda não entendi, não importa, olhe o diagrama abaixo.

3) Depois de entendermos o processo acima, voltamos à recursão. Nossa chamada recursiva é chamar a si mesma em uma função, e a função atual não é destruída, pois a função atual está recursivamente na execução de si mesma, então o processo recursivo , as variáveis ​​de função na pilha foram continuamente colocadas na pilha, porque a pilha do sistema ou o espaço da pilha da máquina virtual é muito pequeno, quando a pilha está cheia e pressionada, fará com que a pilha transborde.


1// 函数
2function f(n){
3    var a = 1;
4    var b = 2;
5    return a + b;
6}

Série recursiva de estrutura de dados e algoritmo

▉ Solução

Então, como podemos resolver essa situação?

Normalmente definimos a profundidade da recursão. O simples entendimento é que se a recursão exceder a profundidade que definimos, sairemos e não recursaremos. Ou o exemplo de fila para jantar, como segue:


 1// 表示递归深度变量
 2let depth = 0;
 3
 4function f(n){
 5    depth++;
 6    // 如果超过递归深度,抛出错误
 7    if(depth > 1000) throw 'error';
 8    // 终止条件
 9    if(n == 1) retun 1;
10    // 递推公式
11    return f(n-1) + 1;
12}

2. Repita recursivamente os elementos

Em alguns problemas recursivos, há um problema de cálculos repetidos, como encontrar a sequência de Fibonacci. Vamos desenhar a árvore recursiva conforme mostrado na figura abaixo. Descobriremos que existem muitos cálculos recursivos repetidos. Cálculos repetidos levarão a um tempo alto complexidade do programa, e é exponencial, o que leva à ineficiência do nosso programa.

Série recursiva de estrutura de dados e algoritmo

▉ Solução

Como devemos resolver o problema da contagem dupla? Alguns amigos pensaram nisso. Salvamos o valor calculado. Antes de cada cálculo recursivo, verifique se os dados salvos contêm os dados. Se houver, vamos usá-los diretamente. Se não, nós calculamos e salvamos. Geralmente usamos uma tabela hash para salvar. (A chamada tabela de hash está na forma de pares de valores-chave, como mapa)


 1// 斐波那契数列改进后
 2let map = new Map();
 3function f(n) {
 4    // 终止条件
 5    if(n == 0) return 0;
 6    if(n == 1) return 1;
 7
 8    // 如果散列表中存在当前计算的值,就直接返回,不再进行递归计算
 9    if(map.has(n)){
10        return map.get(n);
11     }
12
13    // 递推公式
14    let num = f(n-1) + f(n-2);
15    // 将当前的值保存到散列表中
16    map.set(n,num)
17    return num;
18}

3. Alta complexidade recursiva de espaço

Como o armazenamento de variáveis ​​de função durante a recursão requer espaço de pilha adicional, quando a profundidade da recursão é muito profunda, é necessária memória adicional para ocupar muito espaço, portanto, a recursão tem uma complexidade de espaço muito alta.

A última coisa a dizer

No final, posso dizer que é um pouco de sangue de galinha. Muitas pessoas entram em colapso quando se deparam com a recursão, como eu, haha. Não importa quais dificuldades você encontre no futuro, não tenha medo delas, mas trate-as como um desafio. Quando você supera as camadas de dificuldades após uma longa batalha e, finalmente, supera os desafios, você será grato por não desistiu diante das dificuldades.

Sinto profundamente sobre isso. Às vezes me sinto muito impotente em relação ao problema. Embora eu não tenha uma boa universidade, nem bons recursos e ninguém para me concentrar em orientar você, sempre acredito que tudo isso é dado por Deus. o livro do desafio que publiquei, continuarei a trabalhar duro para escrever mais artigos de alta qualidade.

Se você se sentir bem, pode adicionar uma coxa de frango ao cervo! Obrigado novamente por ser um criador de código irreconciliável!

Acho que você gosta

Origin blog.51cto.com/15064450/2602375
Recomendado
Clasificación