Algoritmo Python-1. Quadrado perfeito

Escreva na frente

Esta é uma nota de estudo feita por um caso que encontrei no processo de aprendizagem do Python. O caso vem de "Python Algorithm Guide-Programmer's Classic Algorithm Analysis and Implementation". O código-fonte refere-se a este livro e aos materiais online. Corrija-me se a expressão está errada. Obrigado!

Descrição do Problema

Dado um número inteiro positivo n, encontre vários quadrados perfeitos (por exemplo: 1, 4, 9, ...), faça sua soma igual an, e minimize o número de quadrados perfeitos.

Exemplos de perguntas

Dado n = 12, retorne 3 porque 12 = 4 + 4 + 4;
forneça n = 13, retorne 2 porque 13 = 4 + 9;
forneça n = 15, retorne 4 porque 15 = 1 +1 + 4 + 9.

problema resolvido

No início, minha ideia era usar um método recursivo, cada vez que um número quadrado perfeito máximo menor ou igual an é subtraído e a diferença obtida é atribuída a n, e uma função é usada para recursar, e o número de registros por chamada é +1, até que a diferença obtida seja zero.

Por exemplo, 13-9 =, 4, o número de registros é 1; 4-4 = 0, o número de registros é 2; o último nível da função retorna 2.
Mas o problema é que 12 = 4 + 4 + 4, se você usar essa ideia para obter It is 12 = 9 + 1 + 1 + 1, que retorna 4.
Portanto, esse método não é viável.

Tentei usar o método enumerado para encontrar a lei. Depois de listar dezenas de números, descobri que o número quadrado completo consiste em si mesmo e retorna 1; alguns números, como 10 e 13, são compostos de dois números quadrados completos e retorna 2; como 7, 15, 23, etc. são compostos por quatro números quadrados perfeitos e 3 é retornado; os números restantes são compostos por três números quadrados perfeitos.

Desta forma, o problema é melhor resolvido: como sqrt () a raiz quadrada retorna um número de ponto flutuante, se (int (sqrt (n))) ** 2 for igual ao próprio n, então n é um número quadrado perfeito. Retorne 1; pegue o inteiro de i de 1 a int (sqrt (n)), se i ** 2 + (int (sqrt (ni))) ** 2 = n, então n é elevado ao quadrado por dois Composição de número, retorno 2; em uma série de números que retornam 4, a regra pode ser encontrada como n = 7 + 8k, ou seja, n leva o restante de 8 para obter 7; o número restante retorna 3.

O código-fonte fornecido no livro também funciona da mesma maneira. O código-fonte é o seguinte:

def numSquares(self,n):
        while n % 4 == 0:
            n //= 4
        if n % 8 == 7:
            return 4
        for i in range(n+1):
            temp = i * i
            if temp <= n:
                if int((n-temp) ** 0.5) ** 2 + temp == n :
                    return 1 + (0 if temp == 0 else 1)
            else:
                break
        return 3

O princípio é apenas a regra que obtive com base nas dezenas de números listados, e não entendo um dos loops while, então continuo para o Baidu.

O Baidu apresentou várias soluções para números quadrados perfeitos, incluindo programação dinâmica, métodos de pesquisa de amplitude e profundidade, e o método do teorema dos quatro quadrados é usado aqui.

Teorema da soma dos quatro quadrados de Lagrange: Qualquer número inteiro positivo pode ser expresso como a soma dos quadrados de não mais do que quatro números inteiros.
O número n que satisfaz o teorema da soma quadrada de quatro números (aqui deve ser composto de quatro números, menos de quatro não funcionará), deve satisfazer n = 4 a (8 b + 7)

Desta forma, a operação do loop while pode tornar o processo de cálculo mais fácil.

Coloque a função na classe (esta etapa pode ser omitida), defina a função principal e insira o valor a testar.

if __name__ == '__main__':
    print("输入初始值:")
    n = int(input())
    print ("初始值:",n)
    solution = Solution()
    print ("结果:",solution.numSquares(n))

Os resultados do teste são os seguintes:
Insira a descrição da imagem aqui

Insira a descrição da imagem aqui
Insira a descrição da imagem aqui
Insira a descrição da imagem aqui

Expansão do problema

É possível julgar o número quadrado perfeito e ao mesmo tempo em que números quadrados perfeitos ele consiste?

Inesperadamente, procurei Du Niang novamente para obter ajuda.

No final, encontrei uma solução no artigo "Perfect Square Number" do blogueiro "An Old Ape", mas ele usou a versão Java do código, não olhei com atenção, mas a ideia era muito clara . Nos comentários abaixo, o blogueiro "High Mountain and Flowing Water Cyh" forneceu o código Python.

O código completo é o seguinte:

from  collections  import  deque  as  dq
import  numpy as np
import  math
import pandas as pd
def  perfect(n):
    a=np.repeat(-1,n+1)
    a[n]=n
    q=dq()
    q.append(n)
    sq=pd.Series(range(1,math.floor(math.sqrt(n))*2+1,2)).cumsum().values    
    while q.__len__()>0  and  a[0]<0:
        x=q.popleft()
        l=x-sq
        l=l[l>=0]
        l=l[a[l]==-1]
        q.extend(l)
        a[l]=x
    i=0
    j=a[i]
    while  i<n:
       print(j-i,end=" ")
       i=j
       j=a[i]

Qual é o algoritmo DFS?

DFS (Depth-First-Search) é um tipo de algoritmo de pesquisa. É um método usado mais nas fases iniciais de desenvolvimento do rastreador. Seu objetivo é atingir os nós folha da estrutura pesquisada.

Já entrei em contato com a estrutura de dados antes, e ainda pode ser entendida como a busca do caminho mais curto, encontre a fórmula mais curta do primeiro número do quadrado completo ao último número do quadrado completo, as idéias de implementação específicas e exemplos do código ( pegue n = 14) da seguinte maneira:

1. Crie uma matriz de linha contendo n + 1 números, os primeiros n números recebem um valor de -1 para indicar não explorado, e o n + 1 º número é atribuído n

	a=np.repeat(-1,n+1)
    a[n]=n

Obtenha a = [-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 14]

2. Crie um objeto duque para facilitar o uso de operações de fila e armazene o valor inicial n como o primeiro elemento da fila

	q=dq()
    q.append(n)

Obtenha q = deque ([13]), acesse a entrada do caminho a ser acessado

3. Obtenha todos os números quadrados no intervalo de 1 a n e armazene-os na matriz de linha sq para usar como uma subtração

    sq=pd.Series(range(1,math.floor(math.sqrt(n))*2+1,2)).cumsum().values
    #math.floor(x)取小于等于x的最大整数
    #series是一个一维数组,Pandas会默然用0到n-1来作为series的index,第一列为index,第二列为值
    #cumsum求累计次数
    #values取值
    #最终得到的是小于等于n的所有完全平方数

Obtenha sq = [1 4 9]

4. Comece a pesquisar o caminho mais curto. Cada vez que um número é retirado do início da linha, o valor inicial é o número original n, e a matriz resultante sq é subtraída do número exibido para obter a matriz restante 1. Em desta vez, a primeira etapa do caminho foi realizada. Existem m possibilidades (m é a dimensão da linha sq). A
condição do loop é que ainda haja elementos na fila e o primeiro elemento de a que armazena o sinalizador de acesso é menos que zero

    while q.__len__()>0  and  a[0]<0:
        x=q.popleft()
        l=x-sq

Em seguida, julgue se o número na matriz de resto é maior ou igual a zero, e o caminho com um resto negativo é ilegal e será limpo na matriz de resto; em
seguida, julgue se o resto obtido foi explorado ou se foi foram armazenados na matriz a ser explorada, que não atende às condições Será desmarcada, não há necessidade de repetir a exploração;
após as duas rodadas de atualização acima, o restante na matriz l é o restante que é legal e não foi explorado.

        l=l[l>=0]
        l=l[a[l]==-1]

Em seguida, envie o restante em l para a fila q para a próxima rodada de exploração;
use o restante como um índice e esta rodada de menos x como o valor, atualize a matriz do sinalizador de acesso

        q.extend(l)
        a[l]=x

Até que todos os elementos na fila sejam explorados ou um certo resto se torne 0, o loop termina, o que significa que a busca do caminho mais curto é concluída

O primeiro ciclo:
x = 14
q = deque ([])
l = [13 10 5]
l = [13 10 5] #primeira atualização
l = [13 10 5] # segunda atualização
q = deque ([13 10 5] )
a = [-1 -1 -1 -1 -1 14 -1 -1 -1 -1 14 -1 -1 14 14]
# O sinalizador de acesso do índice 5, 10, 13 é atualizado para 14, o que significa que o valor é obtido subtraindo sq de 14 como o valor subtraído. A
condição do loop é estabelecida e o loop continua

O segundo ciclo:
x = 13
q = deque ([10, 5])
l = [12 9 4]
l = [12 9 4] #primeira atualização
l = [12 9 4] #segunda atualização
q = deque ([10 , 5, 12, 9, 4])
a = [-1 -1 -1 -1 13 14 -1 -1 -1 13 14 -1 13 14 14]
#O índice é 4, 9, O sinalizador de acesso de 12 é atualizado para 13, o que significa que o valor é obtido subtraindo sq de 13 como menos. A
condição do loop é estabelecida e o loop continua

O terceiro ciclo:
x = 10
q = deque ([5, 12, 9, 4])
l = [9 6 1]
l = [9 6 1] #primeira atualização
l = [6 1] #segunda atualização, o índice é o valor existente em 9, remova o elemento 9
q = deque ([5, 12, 9, 4, 6, 1])
a = [-1 10 -1 -1 13 14 10 -1 -1 13 14 -1 13 14 14]
# O sinalizador de acesso do índice 1, 6 é atualizado para 10, o que significa que o valor é obtido subtraindo sq de 10 como subtraído. A
condição de loop é estabelecida e o loop continua

O quarto ciclo:
x = 5
q = deque ([12, 9, 4, 6, 1])
l = [4 1 -4]
l = [4 1] #Primeira atualização, remova -4
l = [] # Em a segunda atualização, 1, 4 foi armazenada em q a ser explorada
q = deque ([12, 9, 4, 6, 1])
a = [-1 10 -1 -1 13 14 10 -1- 1 13 14 -1 13 14 14]
#Status inalterado, a
condição do loop é estabelecida, o loop continua

O quinto ciclo:
x = 12
q = deque ([9, 4, 6, 1])
l = [11 8 3]
l = [11 8 3] #primeira atualização
l = [11 8 3] # 第 A segunda atualização
q = deque ([9, 4, 6, 1, 11, 8, 3])
a = [-1 10 -1 12 13 14 10 -1 12 13 14 12 13 14 14]
#Index é 3, o sinalizador de acesso de 8, 11 é atualizado para 12, o que significa que o valor é obtido subtraindo sq de 12 como o número subtraído. A
condição de loop é estabelecida e o loop continua

O sexto ciclo:
x = 9
q = deque ([4, 6, 1, 11, 8, 3])
l = [8 5 0]
l = [8 5 0] #Primeira atualização
l = [0] # A segunda atualização, 5 foram explorados, 8 foram armazenados em q a serem explorados
q = deque ([4, 6, 1, 11, 8, 3, 0])
a = [9 10 -1 12 13 14 10 -1 12 13 14 12 13 14 14]
# O sinalizador de acesso com índice 0 é atualizado para 9, o que significa que o valor é obtido subtraindo sq de 9 como subtraído. A
condição de loop não é estabelecida e o loop termina

5. O próximo passo é voltar de acordo com o caminho de exploração e tirar o
valor da matriz a quando o resto do caminho mais curto for 0. O valor é usado como o número subtraído do último parágrafo, e é subtraído de si mesmo para obter zero, que é o último parágrafo do caminho. quadrado perfeito, a saída do caminho;
ao mesmo tempo, o valor do índice está em um caminho a ser tomado em um caminho mínimo, com isso para obter um quadrado perfeito de subtração em um caminho, o caminho de saída;
para Por analogia, o número do primeiro caminho é n, e todos os caminhos são retirados.

    i=0
    j=a[i]
    while  i<n:
       print(j-i,end=" ")
       i=j
       j=a[i]

i = 0
j = 9
Primeiro ciclo:
saída 9-0 = 9 #A diferença é o valor deste caminho
i = 9 # O índice do caminho anterior, o número subtraído do próximo caminho
j = 13 # O caminho anterior Subtraído number A
condição do loop é estabelecida, o loop continua

O segundo ciclo:
saída 13-9 = 4
i = 13
j = 14 A
condição do ciclo é estabelecida, o ciclo continua

O terceiro ciclo:
saída 14-13 = 1
i = 14
j = 14 A
condição do ciclo não é estabelecida, o ciclo termina

O valor de saída final é 9 4 1, ou seja, 13 = 9 + 4 + 1 é o caminho mais curto

Pensamento problemático

Quando n = 200 é inserido, o resultado dado pelo programa é 196 4 e, de acordo com nossos cálculos, há outra solução ótima de 100 100. Você pode listar diferentes soluções ótimas? Tenha tempo para explorar novamente.

Escreva no final

A primeira vez que escrevo um blog, é apenas para registros de aprendizagem pessoal. O layout é ruim e as ideias e expressões estão erradas. Corrija-me!

Acho que você gosta

Origin blog.csdn.net/weixin_47585015/article/details/108846046
Recomendado
Clasificación