生成所有小于N的复数

124 阅读7分钟

在这个问题中,我们将看到如何通过探索回文的模式来有效地生成指定范围内的回文数。

目录

1 问题简介
2 解决问题的方法
3 蛮力解决
4 了解宫廷数的模式
5 产生宫廷数的优化方案

问题简介

首先,让我们讨论一下什么是回文数,回文数是一个向后读与向前读相同的序列。

例子

以下是回文数的例子:

RACECAR

它的正读和倒读都是一样的,如下图所示。

palindrome-example-1

让我们再看一个例子:

NURSESRUN

它也会被向前和向后读出,如下图所示。

palindrome-example-2

所以,你看,无论你怎么读,即向前或向后读,都会读出相同的调色板序列。

数字也是如此,一个数字如果向后读和向前读都是一样的,就被称为回文数字。

同位数的例子

下面给出了一些互不相干的数字。
11
101
1221
1123211

你可以看到,无论你怎么读上述数字,这些数字都会被读成一样的,即向前和向后。

解决问题的方法

有2种基本的方法来解决任何给定的问题
1 通过在整个数据集中逐一搜索来找到我们的解决方案
2 在不搜索数据集的情况下产生相关的解决方案

蛮力解决

所以,几乎每个程序员解决问题的第一种方法就是蛮力解决,所以我们来讨论这个问题的蛮力解决方法。

这个问题的蛮力解决方法简单来说就是这样。

算法

*1 从1开始迭代,直到给定的数字,例如N
2 将迭代中的数字称为原数
3 将原数倒过来,称为倒数
4 比较原数倒数
5 如果两者相等,则将原数打印为回文
6 否则将循环中的数字递增1,并转到第2步 重复,直到循环条件为假为止

Python代码

def palindrom_numbers(n):
    for i in range(1,n):
        original_number = str(i)
        reverse_number = original_number[::-1]
        if original_number == reverse_number:
            print(original_number)
      
n = 12
palindrom_numbers(n)

上述代码的时间复杂度超过了O(n),因为反转字符串的操作也需要额外的时间来将字符串转换为其反转形式,这取决于数字的长度,这也是可变的。

因此,这是一个蛮力的解决方案,在这个解决方案中,我们的方法基本上是在整个数据集中逐一找到解决方案。

了解回文数字的模式

现在,我们将了解宫廷数解决方案的模式,这将帮助我们建立一个问题的优化解决方案。让我们再来看看一些回文数字的例子。
*1
22
3333
1221
144441
131
11411
22322

如果我们根据长度对上述数字进行分类,我们会发现有两种类型的回文数字存在,即奇数回文数字(1, 131, 11411 ...)偶数回文数字(22, 3333, 1221, ...)

奇数长度的宫格数

如果我们试图理解奇数长度的调和数,我们会发现其中有一个规律,中间的数字会有所不同,而左右两边的数字是相互映照的。

偶数长度的互不相干的数字

现在试着理解偶数长度的宫格数字存在什么规律,在偶数长度的宫格数字中,我们看到数字的开头是这些数字的镜像,问题是我们如何决定偶数长度的终点和起点,答案很简单,在其长度的基础上将数字分成两部分,第一部分是数字的起点,第二部分是数字的终点。让我们来看看下面的例子。

上述所有数字的长度都是偶数,我们来讨论一下上述数字的1乘1。

  • 22中,数字的长度是2,如果我们把它分成两部分,每一部分的长度是一个数字,所以,2在数字的开始和结束,代表起始数字的镜像。
  • 3333中,数字的两部分,即开始和结束都包含两位数,所以33在数字的开始,它的镜像也是33,在数字的结束。
  • 1221中,数字的两部分都包含两个数字,开始部分是12,结尾部分是它的镜像21,现在看到这个例子,偶数长度的复数模式得到了很好的解释。

所有偶数长度的回文数都有上述的模式。

产生调和数的优化方案

现在我们理解了宫格数的模式,所以我们可以建立一个优化的解决方案来解决给定的问题。所以,现在我们知道有两种类型的回文数,即偶数和奇数,存在于任何给定的范围内。所以,如果我们稍加思考,就能想出一种算法,可以在给定的范围内生成两种类型的回文数。

比方说,我们要生成所有小于104的复数。

算法

*1 称呼给定的数字n(在我们的例子中是104)
2 从数字1开始迭代,称之为i
3 用i生成偶数长度的宫格(用一些数学公式),称之为pal
4 打印pal
5 将i增加1
6 转到步骤3,重复这一过程,直到pal小于n

再次使用上述算法生成奇数长度的宫格(即在上述算法的第3步生成奇数长度的宫格)。

当上述算法完成后,所有小于给定数字(104)的宫格都已生成。

现在,为了使一切都能理解,让我将上述算法分为两部分,一部分将生成所有偶数长度的宫廷线,另一部分将生成所有奇数长度的宫廷线,最后,我将合并这两部分,设计一个单一的代码,生成所有小于指定范围的宫廷线。

偶数长度宫廷诗的代码

def generate_even_length_palindromes(i):
    n = i
    while( n > 0):
        i = i * 10 + (n % 10)
        n = n // 10
    return i

让我们对12这个数字试运行上述代码

  • 最初n=12
  • 我们的条件将是真实的,i将是12 * 10 + (2) = 122
  • 现在,执行这个语句后n将是1 n*= n // 10*
  • 条件仍然为真,i将是122 * 10 + (1) = 1221
  • 现在,执行这条语句后,n将为0 n*= n // 10*
  • 条件是假的,现在从函数中返回的i将是1221,这是一个偶数长度的回文。

这就是上述函数生成偶数长度的宫锁连环套的过程,你可以对任何数字进行干运行或执行。

奇数长度回文的代码

def generate_odd_length_palindromes(i):
    n = i // 10
    while( n > 0):
        i = i * 10 + (n % 10)
        n = n // 10
    return i

让我们对数字12进行模拟运行上述代码

  • 最初n=1
  • 我们的条件将是真实的,i将是12 * 10 + (1) = 121
  • 现在,执行这个语句后n将为0 n*= n // 10*
  • 条件是假的,现在从函数中返回的i将是121,这是一个奇数长度的回文。

这就是上述函数如何生成奇数长度的回文,你可以干巴巴地运行它或对任何数字执行它。

生成所有小于N的复数的完整代码

def generate_palindromes(i, is_odd):
    # logic/ mathematical formula
    # to generate palindromes
    if (is_odd):
        n = i // 10
    else:
        n = i
    while(n > 0):
        i = i * 10 + (n % 10)
        n = n // 10
    return i
    
for k in range(2):
    # this loop has only two iterations,
    # 1st to generate even length
    # 2nd to generate ood length
    i = 1
    while(generate_palindromes(i, k%2) < 100000):
        # iterate and generate a palindrom until
        # it greater than the given range
        print(generate_palindromes(i,k%2))
        i += 1
    

以上是生成给定范围内所有宫廷诗的完整代码。它是上述两个函数(generate_odd_length_palindromes, generate_odd_length_palindromes)的乘积,我已经解释过了,以使你理解解决这个问题的整个逻辑。