python蓝桥杯备赛重要排序方法复盘(程序员面试算法宝典)

蓝桥杯备赛注意事项

持之以恒,循序渐进

知识有连贯性,只有循序渐进的学习和知识积累,才能不断的深入。
荀子曰:“不积跬步,无以至千里;不积小流,无以成江海。”哲学上说,没有量变的积累,就没有质变上的飞跃,成功离不开积累。
积累是源泉,积累是力量,只有踏踏实实的积累,才会有实实在在的收获。
学习是一个循序渐进持之以恒的过程。要想在学习上一蹴而就,成为大学问家是不可能的。华罗庚所言:“面对悬崖峭壁,一百年也看不出一条缝来,但用斧凿,能进一寸进一寸,得进一尺进一尺,不断积累,飞跃必来,突破随之。就是讲的这个道理。

关于比赛时的小技巧

比赛的时候,因为考生来考场时间早晚不一,离正式考试会有一段时间,这段时间监考官会讲一些考试的注意事项,当了解完这些如果还没开考的话,你可以提前在你的电脑上写一些你平时积累的通用函数(算法),例如与冒泡排序、栈、二叉树构建、贪心、动态规划、dp、等等一些通用方法…(请尽情发挥想象),然后考试的时候直接调用函数或者方法即可

专题备战2-----经典排序算法

排序是算法的入门知识,其思想可以用于很多算法中,而且因为排序算法实现代码较少,应用较为广泛,所以在备赛时、程序员面试笔试中,求职者经常被问及排序算法及其相关的问题。虽然排序算法名目繁多,各不相同,但万变不离其宗,只要熟悉了算法思想,灵活运用它们也非难事。一般在面试笔试中,最常考的排序算法是快速排序和归并排序,而插入排序、冒泡排序、堆排序、基数排序、桶排序等算法也经常被提及。

如何进行选择排序

【问题描述】
给定一组数组,从小到大输出结果(升序)
【分析与解答】
选择排序是一种简单直观的排序算法,它的基本原理如下:对于给定的一组记录,经过第一轮比较后得到最小的记录,然后将该记录与第一个记录进行交换;接着对不包括第一个记录以外的其他记录进行第二轮比较,得到最小的记录并与第二个记录进行位置交换;重复该过程,直到进行比较的记录只有一个时为止。以数组{38,65,97,76,13,27,49}为例,具体步骤如下:
第一次排序后:13 [65 97 76 38 27 49]
第二次排序后:13 27[97 76 38 65 49]
第三次排序后:13 27 38 [76 97 65 49]
第四次排序后:13 27 38 49 [97 65 76]
第五次排序后:13 27 38 49 65 [97 76]
第六次排序后:13 27 38 49 65 76 [97]
最后排序结果:13 27 38 49 65 76 97
选择排序是一种不稳定的排序方法,最好、最坏和平均情况下的复杂度都为O(n^2),空间复杂度为O(1)

def select_sort(list):
    #选择排序
    #升序
    count=len(list)
    for i in range(0,count):
        min=i
        for j in range(i+1,count):
            if list[min]>list[j]:
                min=j
        list[min],list[i]=list[i],list[min]
    return list
if __name__=="__main__":
    list=[38,65,97,76,13,27,49]
    print("排序前:")
    for i in list:
        print(i)
    print("排序后")
    for j in select_sort(list):
        print(j)

【计算结果】
排序前:38 65 97 76 13 27 49
排序后:13 27 38 49 65 76 97
【总结】
选择排序是一种不稳定的排序方法,最好、最坏和平均情况下的复杂度都为O(n^2),空间复杂度为O(1)

如何进行插入排序

【问题描述】
定义插入排序函数,实现列表升序排序。
【分析与解答】
对于给定的一组记录,初始时假设第一个记录自成一个有序序列,其余的记录为无序序列;接着从第二个记录开始,按照记录的大小依次将当前处理的记录插入到之前的有序序列中,直至最后一个记录插入到有序序列中为止。以数组{38,65,97,76,13,27,49}为例,具体步骤如下:
第一步插入38以后:[38] 65 97 76 13 27 49
第二步插入65以后:[38 65] 97 76 13 27 49
第三步插入97以后:[38 65 97] 76 13 27 49
第四步插入76以后:[38 65 76 97] 13 27 49
第五步插入13以后:[13 38 65 76 97] 27 49
第六步插入27以后:[13 27 38 65 76 97] 49
第七步插入49以后:[13 27 38 49 65 76 97]

def insert_sort(list):
    #插入排序
    #升序
    count=len(list)
    for i in range(1,count):
        key=list[i]
        j=i-1
        while j>=0:
            if list[j]>key:
                list[j+1]=list[j]
                list[j]=key
            j-=1
    return list
if __name__=="__main__":
    list=[38,65,97,76,13,27,49]
    print("排序前:")
    for i in list:
        print(i)
    print("排序后")
    for i in insert_sort(list):
        print(i)

【运行结果】
排序前:38 65 97 76 13 27 49
排序后:13 27 38 49 65 76 97
【总结】
插入排序是一种稳定的排序方法,最好情况下的时间复杂度为O(n),最坏情况下的时间复杂度为O(n^2),平均情况下的时间复杂度为O(n的平方),空间复杂度为O(1)

如何进行冒泡排序

【题目描述】
定义冒泡排序函数,实现列表升序排序。
【分析与解答】
冒泡排序顾名思义就是整个过程像气泡一样往上升,单向冒泡排序的基本思想是(假设由小到大排序):对于给定的n个记录,从第一个记录开始依次对相邻的两个记录进行比较,当前面的记录大于后面的记录时,交换其位置,进行一轮比较和换位后,n个记录中最大记录位于第n位,然后对前 (n-1)个记录进行第二轮比较;重复该过程直到进行比较的记录只剩下一位为止。
以数组{36,25,48,12,25,65,43,57}为例,具体步骤如下:
初始状态:[36 25 48 12 25 65 43 57]
1次排序:[25 36 12 25 48 43 57 65]
2次排序:[25 12 25 36 43 48] 57 65
3次排序:[12 25 25 36 43] 48 57 65
4次排序:[12 25 25 36] 43 48 57 65
5次排序:[12 25 25] 36 43 48 57 65
6次排序:[12 25] 25 36 43 48 57 65
7次排序:[12] 25 25 36 43 48 57 65
【运行结果】
排序前:36 25 48 12 25 65 43 57
排序后:12 25 25 36 43 48 57 65
【代码实现】

def bubble_sort(list):
    #冒泡排序
    #升序
    count=len(list)
    for i in range(count-1):
        for j in range(count-i-1):
            if list[j]>list[j+1]:
                list[j],list[j+1]=list[j+1],list[j]
    return list
if __name__=="__main__":
    list=[36,25,48,12,25,65,43,57]
    print("排序前:")
    for i in list:
        print(i)
    print("排序后")
    for i in bubble_sort(list):
        print(i)

【总结】
冒泡排序是一种稳定的排序方法,最好情况下的时间复杂度为O(n),最坏情况下的时间复杂度为O(n^2),平均情况下的时间复杂度为O(n的平方),空间复杂度为O(1)

如何进行归并排序

【问题描述】
定义归并排序函数,实现列表升序排序。
【分析与解答】
归并排序是利用递归与分治技术将数据序列划分成越来越小的半子表,再对半子表排序,最后再用递归步骤将排好序的半子表合并成越来越大的有序序列。其中代表的是递归的意思,即递归的将数组折半的分离为单个数组。
【代码实现】

def merge(left,right):
    i,j=0,0
    result=[]
    while i<len(left) and j<len(right):
        if left[i]<=right[j]:
            result.append(left[i])
            i+=1
        else:
            result.append(right[j])
            j+=1
    result+=left[i:]
    result+=right[j:]
    return result

def merge_sort(list):
    #归并排序
    if len(list)<=1:
        return list
    mid=len(list)//2
    left=merge_sort(list[:mid])
    right=merge_sort(list[mid:])
    return merge(left,right)
if __name__=="__main__":
    list=[36,25,48,12,25,65,43,57]
    print("排序前:")
    for i in list:
        print(i)
    print("排序后")
    for i in merge_sort(list):
        print(i)
    

【运行结果】
排序前:36 25 48 12 25 65 43 57
排序后:12 25 25 36 43 48 57 65
【总结】
二路归并的过程需要进行logn次,每一趟归并排序的操作,就是将两个有序子序列进行归并,而每一对有序子序列归并时,记录的比较次数均小于等于记录的移动次数,时间复杂度为O(nlogn),空间复杂度为O(n)。

如何进行基数排序

【题目描述】
定义归并排序函数,实现列表升序排序。
【分析与解答】
基数排序属于分配式排序,又称桶子法,排序过程就是将最低位优先法用于单关键字的情况。

import math
def radix_sort(list,radix=10):
    k=int(math.ceil(math.log(max(list),radix)))
    bucket=[[] for i in range(radix)]
    for i in range(1,k+1):
        for j in list:
            bucket[j/radix**(i-1)%(radix**i)].append(j)
        del list[:]
        for z in bucket:
            list+=z
            del z[:]
    return list
if __name__=="__main__":
    list=[36,25,48,12,25,65,43,57]
    print("排序前:")
    for i in list:
        print(i)
    print("排序后")
    for i in radix_sort(list):
        print(i)
    

【运行结果】
排序前:36 25 48 12 25 65 43 57
排序后:12 25 25 36 43 48 57 65

如何判断一个数是不是某个数的平方

【题目描述】
设计一个算法,判断一个数是不是某个数的平方,不能使用开方运算。例如16就满足条件,因为它是4的平方;而15则不满足条件,因为不存在一个数使得平方值为15.
【分析与解答】
方法一:直接计算法:
由于不能使用开方运算,因此最直接的方法就是计算平方。主要思路为:对1到n的每个数i计算他的平方m,如果m<n,那么继续遍历下一个值(i+1),如果m==n,那么说明n是某个数的平方,如果m>n,那么说明n不能表示成某个数的平方。
由于这种方法只需要遍历1到n[0.5]就可以得出结果,因此算法时间复杂度为O(n[0.5])

def isPower(n):
    if n<=0:
        print(str(n)+"不是自然数")
        return False
    i=1
    while i<n:
        result=i*i
        if result==n:
            return True
        elif result>n:
            return False
        i=i+1
if __name__=="__main__":
    n1=15
    n2=16
    if isPower(n1):
        print(str(n1)+"是某个自然数的平方")
    else:
        print(str(n1)+"不是某个自然数的平方")
    if isPower(n2):
        print(str(n2)+"是某个自然数的平方")
    else:
        print(str(n2)+"不是某个自然数的平方")

【运行结果】
15不是某个自然数的平方
16是某个自然数的平方
方法二:二分查找法:
与方法一类似,这种方法的主要思路还是查找1~n的数字中,是否存在一个数m,使得m的平方为n。只不过查找的过程中使用二分查找的方法。具体思路为:首先判断mid=(1+n)/2的平方power与m的大小,如果power>m,那么说明在[1,mid-1]区间继续查找,否则在[mid+1,n]区间继续查找。
由于这种方法使用了二分查找的方法,因此时间复杂度为O(logn),其中,n为数的大小。

def isPower(n):
    low=1
    high=n
    while low<high:
        mid=(low+high)/2
        result=mid*mid
        #接着在1到mid-1
        if result>n:
            high=mid-1
        elif result<n:
            low=mid+1
        else:
            return True
    return False
        

if __name__=="__main__":
    n1=15
    n2=16
    if isPower(n1):
        print(str(n1)+"是某个自然数的平方")
    else:
        print(str(n1)+"不是某个自然数的平方")
    if isPower(n2):
        print(str(n2)+"是某个自然数的平方")
    else:
        print(str(n2)+"不是某个自然数的平方")

如何不使用除法操作符实现两个正整数的除法

【问题描述】
如何不使用除法操作符实现两个正整数的除法?
【分析与解答】
方法一:减法:
被除数不断减去除数,直到相减的结果小于除数,商就是相减的次数,余数为相减后的差。

def divide(m,n):
    count=0 #记录相减的次数
    while m>n:
        m=m-n
        count=count+1
    remain=m #记录余数
    print("商:"+str(count)+"余数:"+str(remain))
if __name__=="__main__":
    m=14
    n=4
    divide(m,n)

【运行结果】
商:3余数:2
方法二:移位法:
方法一所采用的减法操作,还可以用等价加法操作来实现。例如在计算17除以4的时候,可以尝试41,42(4+4),43(4+4+4),直到计算结果大于14的时候就很容易求出商和余数,但是效率较低。下面介绍另外一种增加递增速度的方法:以2的指数进行递增(取2的指数的原因是,2的指数操作可以通过移位操做来实现,有更高的效率),计算41,42,44,48,由于48>17,然后接着对17-4*4=1,进入下一次循环用相同的方法进行计算。

def divide(m,n):
    result=0 #记录相减的次数
    while m>=n:
        multi=1
        while multi*n<=(m>>1):
            multi<<=1
        result+=multi
        m-=multi*n
    print("商:"+str(result)+"余数:"+str(m))
if __name__=="__main__":
    m=14
    n=4
    divide(m,n)

如何只使用+=操作符实现加减乘除运算

【问题描述】
要求只能使用+=操作来实现加减乘除运算?
【分析与解答】
(1)加法操作:实现a+b的基本思路为对a执行b次+=操作即可;
(2)减法操作:实现a-b(a>=b)的基本思路为:不断对b执行+=操作,直到等于a为止,过程中记录+=操作的次数;
(3)乘法操作:实现ab的基本思路为:利用已经实现的加法操作把a相加b次,就得到了ab的值;
(4)除法操作:实现a/b的基本思路为:利用乘法操作,使b不断乘以1,2,…n,直到b*n>b时,就可以得到商为n-1。
【代码实现】

def add(a,b):
    '''
    方法功能:用+=实现加法操作(限制条件:至少有一个非负数)
    输入参数:a,b都是整数,且有一个非负数
    返回值:a+b
    '''
    if a<0 and b<0:
        print("无法计算")
        return -1
    if b>=0:
        i=0
        while i<b:
            a+=1
            i+=1
        return a
    else:
        i=0
        while i<a:
            b+=1
            i+=1
        return b
def minus(a,b):
    '''
    实现功能:用+=实现减法操作(限制条件:被减数大于减数)
    输入参数:a,b都是整数且a>=b
    返回值:a-b
    '''
    if a<b:
        print('无法计算')
        return -1
    result=0
    while b!=a:
        b+=1
        result+=1
    return result
def multi(a,b):
    '''
    实现功能:用+=实现乘法操作(限制条件:两个数都为整数)
    输入参数:a,b都是正数
    返回值:a*b
    '''
    if a<=0 or b<=0:
        print('无法计算')
        return -1
    result=0
    i=0
    while i<b:
        result=add(result,a)
        i+=1
    return result
def divide(a,b):
    '''
    实现功能:用+=实现除法运算(限制条件:两个数都为整数)
    输入参数:a,b都为非负数
    返回值:a/b
    '''
    if a<=0 or b<=0:
        print('无法计算')
        return -1
    result=1
    tmpMulti=0
    while True:
        tmpMulti=multi(b,result)
        if tmpMulti<=a:
           result+=1
        else:
            break
    return result-1
if __name__=="__main__":
    print('和:'+str(add(3,4)))
    print('差:'+str(minus(3,4)))
    print('积:'+str(multi(3,4)))
    print('商:'+str(divide(3,4)))

【运行结果】
和:7
无法计算
差:-1
积:12
商:0

学好数学的秘籍

“数学是工具而非问题,是手段而非目的”
在数学的学习中,首要的问题是明确需求。作为非数学专业出身的“外行”,我们使用数学的目的不是顶天,而是立地;不是上下求索艰深的理论问题,而是将生活中的具体问题抽象化,进而加以解决。

理解数学的工具属性就会自然而然地引出了数学学习中的另一个关键点,那就是工具设计的出发点,也就是所谓的数学思想与数学逻辑。

任何一个工具都不是平白无故地设计出来的,它必然要解决某个特定的问题,比如线性代数与矩阵论是对具体对象的抽象表示与运算,比如概率论和数理统计是对不确定性及其定型定量表示的建模。因此,在掌握每一种数学工具的微观技巧之前,理解它们的宏观目标是更加重要的。只有掌握了工具诞生的背景与目的,才有可能有效地使用它们。

总结起来,我对数学学习的几点拙见是:把握数学的工具属性,学习具体方法时先溯因再求果,勤于思考解决相同问题的不同方法,与解决不同问题的相同方法之间的联系与区别。希望这几条建议能够在数学的学习中助你一臂之力。

总结

(一) 心理准备:蓝桥杯不是ACM,远远不是,没加过实验室就肯定不行的心理对比赛想来未必有好处。单单我认识的,不是实验室的都有四五个拿到国二或者国三的水平,由此可见跟实验室关系并不很大。

(二) 知己知彼:我觉得是这是参加比赛最重要的一点。参加比赛前干什么?当然是真题最好(我觉得四六级也是这样啊)毕竟组委会经过反复斟酌出的题目肯定质量要比那些什么乱七八糟的题目更准确地把握好难度。建议从官网上下最近两次的省赛题,再前两年的可以百度搜,网上也都有。其实当你都做了会发现,蓝桥杯出题就出一个套路。

(1)题目一共有十道,七道小题,三道编程题,每道题分数呈递增(基本是根据难度定的)

(2)比较理智的估计自己的水平。(我觉得干什么都不能眉毛胡子一把抓,这样的结果往往是什么都抓不住)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值