【Python】杨辉三角中的排成一列编号的问题

news2024/12/28 5:47:04

题目描述

下面的图形是著名的杨辉三角形:
在这里插入图片描述
如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列: 1,1,1,1,2,1,1,3,3,1,1,4,6,4,1,⋯

给定一个正整数 N,请你输出数列中第一次出现 N是在第几个数?

输入描述
输入一个整数 NNN。

输出描述
输出一个整数代表答案。

输入输出样例
示例:输入6,输出13

评测用例规模与约定
对于 20% 的评测用例,1≤N≤10​; 对于所有评测用例,1≤N≤1000000000

运行限制
最大运行时间:1s
最大运行内存: 256M

初步分析

如果直接利用每个数字等于上一行的左右两个数字之和来逐个遍历暴力求解,对于N等于10000000000的情况,没有一个小时电脑算不出来,不符合运行时间限制的1s的要求。
所以要解这一题,必须通过杨辉三角的性质来解决。

杨辉三角的性质

在这里插入图片描述

  1. 杨辉三角的第n行有n+1项,比如第0行有1项,所以杨辉三角的每一行呈等差数列式递增

  2. 杨辉三角的前n行的数字个数(等差数列前n项和):[(2+n)(n+1)]/2

  3. 杨辉三角的第n行第m个数字可以使用C(n,m)来表示,其中C(n,m)的计算方式是:
    在这里插入图片描述

  4. 杨辉三角左右对称,对称轴是C(2k,k), k=0,1,2,3,…n-1,n

深入分析

  1. 如果想要求杨辉三角中某一个数字的编号,需要根据杨辉三角的特性来求,
    第一步,需要求出这个数字是第几行的第几个数字,比如说我们使用某种方法求出数字N位于第n行的第m个位置;
    第二步,求n-1行之前一共有多少个数字(包括第n-1行),(利用等差数列求和公式可以知道n-1行之前一共有[n(n+1)]/2个数字)
    第三步,N位于第n行的第m个位置,所以N的编号就是:[n(n+1)]/2+(m+1)
    在这里插入图片描述

  2. 因为题目让我们求正整数 N第一次出现 的位置,那么这个位置一定在对称轴的左边。

  3. 如果沿着对称轴向左下角延申,数字会越来越大
    在这里插入图片描述

  4. 斜行和对称轴的关系:第k斜行在对称轴的位置的数字是:C(2k,k)。

  5. 所以如果拿着N和对称轴上的每一个数字比较(从上往下),在第k-1斜行时N比对称轴上的数字大,在第k行时N比对称轴上的数字小,说明N一定在第k斜行之前(不包括第k斜行),但是不一定在第k-1斜行,有可能在第1,2,3,…,k-1斜行中的任意一行。

  6. 这时候只需要倒过来从第k-1斜行开始,k-1,k-2,…逐行查找,直到找到N为止即可

  7. 因为在每一个斜行上的数字可能很多,所以可以在每一个斜行上使用二分查找提高检索速度。在每一个斜行使用二分查找的方法:
    二分查找必须有一个查找上限和一个查找下限,查找下限已经有了(每一个斜行在对称轴的位置的数字最小,它的m是下限)
    查找上限:求查找上限必须要知道最坏的查找情况是多少。
    在这里插入图片描述

  8. 在编写代码时,需要计算C(n,m),为了使计算更加简单,我们把公式化简一下:
    在这里插入图片描述

代码

完整的代码如下:

import datetime


def C(n, m):
    """第一步,编写一个计算C(n,m)的函数"""
    result = 1
    num = m
    for i in range(0, num):
        result *= (n - i) / (m - i)

    return int(result)  # 因为计算出来的结果是浮点数,但是我们要的是整型,所以类型转换


def searchLine():
    """第二步,通过对称轴找到N所在的斜行最多不会超过多少"""
    """对称轴的通式:C(2k,k),k=0,1,2,..."""
    num = 0
    while True:
        if N < C(2 * num, num):  # 如果N比某一个斜行上对称轴上的值小了,说明N一定不会在这一斜行及其以后的斜行出现了,因为最小的值都比N大
            break
        num += 1
    print('在第', int(num-1), '斜行之前(包括)')
    return num-1  # N会出现在0,1,2,3,..,num中的任意一斜行斜行是作为C(n,m)中的m的


def binarySearch(low, high, n, k):  # low:查找下限(是C(n,m)中的n),high:查找上限(也是C(n,m)中的n),n:待查找的数字,k:目前正在第k斜行行进行查找(是C(n,m)中的m)
    """第三步,定义一个二分查找函数,"""

    while low <= high:
        middle = (low + high) // 2  # 因为第几行第几行只能是整数,不存在3.5行
        middleNumber = C(middle, k)  # 第k斜行的第middle行的数字,也可以说是第middle+1行的第k+1个数字
        if n == middleNumber:  # 如果n和第k斜行的第middle行的数字相等
            """算出编号(公式是:n(n-1)/2+(m+1))"""
            print(int(middle * (middle + 1) / 2) + k + 1)
            return True
        elif n > middleNumber:
            low = middle + 1
        elif n < middleNumber:
            high = middle - 1

    return False  # 没找到返回False


def searchLocation():
    """第四步,从斜行num开始,从里到外,逐个斜行开始寻找N的位置"""
    """在每一个斜行内,使用二分查找"""
    maxLine = searchLine()  # 获得最大斜行,从第一斜行开始
    for m in range(maxLine, -1, -1):  # maxLine,maxLine-1,..,2,1
        flag = binarySearch(2*m, N, N, m)
        if flag:  # 如果找到了
            return


if __name__ == '__main__':
    N = int(input())
    startTime = datetime.datetime.now()
    searchLocation()
    endTime = datetime.datetime.now()
    print('查找时间:', (endTime - startTime).microseconds*10**-3, 'ms')

最后附上使用 每个数字等于上一行的左右两个数字之和 来逐个遍历暴力求解的代码,你可以看看这种方法到底需要多少时间才能运行出来,反正我运行了20分钟是没有运行出来。

"""for循环,求出N在第几斜行(每次加以行),
当出现斜行的第一个数大于N时(此时处在第i斜行,从零开始),
此时N就在第i-1斜行,遍历i-1斜行就行了"""
import time

s = [1, 1]  # 第二行的数
n = int(input('输入n的值:'))
flag = True
count = 3  # 前两行的总个数是3
fl = 0  # 如果fl > 10000000000 直接退出就行

startTime = time.time()
if n == 1:
    print(1)
else:
    while flag:
        if fl > 10000000000:
            break
        temp = [1]
        length = len(s)
        for i in range(0, length - 1):
            temp.append(s[i] + s[i + 1])
            if temp[-1] == n:  # 如果找到n了退出循环
                flag = False
                break
        temp.append(1)

        count += len(temp)

        s = temp  # 让s存储下一行的数据

        fl += 1

    print(count - 1)

endTime = time.time()
print('运行时间:', endTime - startTime)

参考链接
https://blog.csdn.net/m0_62277756/article/details/122690022

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/146818.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Go语言设计与实现 -- 内存管理器

不同的编程语言选择不同的方式管理内存&#xff0c;本节会介绍Go语言内存分配器。 Go内存分配的设计思想是&#xff1a; 内存分配算法采用Google的TCMalloc算法&#xff0c;每个线程都会自行维护一个独立的内存池&#xff0c;进行内存分配时优先从该内存池中分配&#xff0c;…

第十八章Vue的学习

文章目录什么是VueVue.js的官网介绍环境配置基本语法声明式渲染绑定元素属性双向数据绑定条件渲染列表渲染事件驱动侦听属性Vue对象生命周期什么是Vue 对于Java程序来说&#xff0c;我们使用框架就是导入那些封装了**『固定解决方案』的jar包&#xff0c;然后通过『配置文件』…

CSS3 之选择器

文章目录1、关系性选择器&#xff1a;EFE~F2、属性选择器3、伪元素选择器4、伪类选择器(被选中的元素的一个种状态)calc1、关系性选择器&#xff1a;EFE~F 2、属性选择器 E[attr~“val”]E[attr|“val”]E[attr^“val”]E[attr$“val”]E[attr*“val”]3、伪元素选择器 E::pl…

CesiumLab对BIM模型的输入格式要求 CesiumaLab系列教程

BIM 模型和手工模型最大的区别在于几点&#xff1a; 1.建模目标不同&#xff0c;手工模型的目的是为了可视化&#xff0c;就是为了看的见&#xff0c;看不见的东西能省则省。BIM 完全是按照一些工程标准去创建的&#xff0c;比如路面可能有多个层代表了不同的物理层。手工模型…

windows编译Paraview源码

目录一. 环境准备二. 编译1. CMake2. Visual Studio一. 环境准备 下载基本所需&#xff1a; paraview官方给了编译文档&#xff1a;https://github.com/Kitware/ParaView/blob/master/Documentation/dev/build.md 所需要的基础有&#xff1a; 如图&#xff1a;&#xff08;进入…

2022我的年度总结-- AI遮天之路

我是一个普普通通的大学生&#xff0c;我的博客记录了我学习编程以来共计1年多的水平&#xff0c;我希望能把自己大学的经历、选择、困惑等与同样身处大学&#xff0c;选择AI方向不知如何发展的人进行分享&#xff0c;因此写了这篇年终总结。另外&#xff0c;对于一些刚刚开始写…

重磅!华为更新职业认证架构刷新和重认证规则

尊敬的各位朋友&#xff0c;感谢您一直以来对华为认证的支持&#xff01; 为匹配华为公司未来长期战略&#xff0c;紧随ICT技术演进趋势&#xff0c;自2023年1月1日起&#xff0c;华为职业认证将启用全新的架构体系和重认证规则&#xff0c;请您关注。 华为职业认证架构刷新 …

新年新希望--爱摸鱼的美工(12)

年近了&#xff0c;上班途中依然匆忙 看女孩子们渐渐开始倒腾 做了新发型&#xff0c;做了美美的指甲 换上了新衣服&#xff0c;买了新包 电话里讨论着 去哪里过年&#xff0c;买什么年货 好像以前的我也这样 今年挣得少了&#xff0c;不想添新衣&#xff08;不能&#xff09; …

【条理清晰】在 Windows 上安装 MySQL

下载 MySQL 安装程序安装 MySQL 数据库安装示例数据库下载 MySQL 安装程序 在本教程中&#xff0c;我们展示如何在 Windows 平台上下载和安装 MySQL 的详细步骤。 在 Windows 平台上安装 MySQL 很简单&#xff0c;并不需要太复杂的步骤。按照本文的步骤操练起来就可以了。 我…

一体化Ethercat通信伺服电机在汇川H5U PLC上的应用案例介绍(下)

内容介绍了一体化低压伺服Ethercat通信的电机在汇川H5UPLC上的使用&#xff0c;一体化Ethercat通信伺服电机在汇川H5U PLC上的应用案例介绍(上)主要讲解环境的搭建以及使用AutoShop软件的在线调试功能&#xff0c;简单控制电机位置、速度模式运行。那么本篇我们就来讲解下使用汇…

【Kotlin】空安全 ② ( 手动空安全管理 | 空安全调用操作符 ? | let 函数结合空安全调用操作符使用 )

文章目录一、手动空安全管理二、空安全调用操作符 ?三、let 函数结合空安全调用操作符使用一、手动空安全管理 Kotlin 语言中 , 变量类型 分为 可空类型 和 非空类型 , 默认状态 下 , 变量是 非空类型 的 , 如果使用 类型? 将变量声明为 可空类型 , 那么就需要使用 手动安…

【C语言进阶】动态内存管理

1. 为什么存在动态内存分配我们已经掌握的内存开辟方式有&#xff1a;int val 20;//在栈空间上开辟四个字节 char arr[10] {0};//在栈空间上开辟10个字节的连续空间但是上述的开辟空间的方式有两个特点&#xff1a;1. 空间开辟大小是固定的。2. 数组在申明的时候&#xff0c;…

JavaWeb复习

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目…

【迅为iMX6Q】开发板 u-boot 2022.04 SD卡 启动

相关参考 【迅为iMX6Q】开发板 u-boot 2015.04 SD卡 启动 【迅为iMX6Q】开发板 u-boot 2020.04 SD卡 启动 开发环境 win10 64位VMware Workstation Pro 16ubuntu 22.04【迅为imx6q】开发板&#xff0c; 2G DDR uboot-imx 下载 使用 NXP 官方提供的 uboot-imx&#xff0c;代…

TreeList-关闭默认显示的右击菜单

需要给控件添加自定义的右击菜单&#xff0c;所以就造成了冲突&#xff0c;导致右击时只弹出控件自带的菜单而没弹出我自定义的菜单&#xff0c;现在把关闭默认菜单的方法记录一下

数据库,计算机网络、操作系统刷题笔记27

数据库&#xff0c;计算机网络、操作系统刷题笔记27 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开发&#xff0c;测开 测开的话&#xff0c;你就得学数据库&#xff0c;sql&#xff0c;oracle…

解决在Win10上安装VMware Workstation虚拟机不可用

一、说明 这是近几年安装虚拟机存在的问题&#xff0c;这里首先说明&#xff0c;以下信息纯粹来自VMware的参考文档&#xff0c;本人的实现不太成功&#xff0c;期望得到更好的WMware软件进行尝试。 二、错误提示 在 Windows 10 主机上&#xff0c;VMware Workstation 中显示“…

2023/1/7 Vue学习笔记-3-组件的理解

1 对组件的理解 模块与组件、模块化与组件化&#xff1a; 1.模块&#xff1a; &#xff08;1&#xff09;理解&#xff1a;向外提供特定功能的js程序&#xff0c;一般就是一个js文件 &#xff08;2&#xff09;为什么&#xff1a;js文件很多很复杂 &#xff08;3&#xff09;作…

【Linux工具】-vim介绍

Vim使用一&#xff0c;Vim的四种模式二&#xff0c;命令模式1,复制&#xff0c;剪切&#xff0c;粘贴2&#xff0c;撤销操作3&#xff0c;光标的移动4&#xff0c;替换&#xff0c;选中&#xff0c;删除5&#xff0c;h j k l键的使用6&#xff0c;多行注释&#xff0c;去多行注…

2023-01-07:hyper/docker-registry-web是registry的web界面工具之一。请问部署在k3s中,yaml如何写?

2023-01-07&#xff1a;hyper/docker-registry-web是registry的web界面工具之一。请问部署在k3s中&#xff0c;yaml如何写&#xff1f; 答案2023-01-07&#xff1a; yaml如下&#xff1a; apiVersion: apps/v1 kind: Deployment metadata:labels:app: docker-registry-webna…