HNUCM-OJ 2023年春季学期《算法分析与设计》练习6

问题 A: 第k小元素问题

题目描述

输入一个整数数组,请求出该数组的第k小元素。要求时间复杂度为O(n)。

输入

每组输入包括两行,第一行为一个整数数组,两个数字之间用空格隔开;第二行为k值。数组中元素个数小于1000。

输出

输出第k小元素的值。

样例输入 Copy

2 5 6 1 8 7 9
2

样例输出 Copy

2

思路:可以直接对数组排序,取下标为K-1的数。

  也可以按照老师的上课的知识,对数组分区判断是在前一部分还是后一部分

while True:
    try:
        nums, k = [int(i) for i in input().split()], int(input())
        nums.sort()
        for i in range(len(nums)):
            if i == k - 1:
                print(nums[i])
    except:
        break

问题 B: 找中位数

请设计一个算法,不排序,快速计算出一个无序数列的中位数。 时间复杂度要求为O(n)。
如果有奇数个元素,中位数则是数组排序后最中间的那个数字。
如果是偶数个元素,中位数则是数组排序后最中间两个元素的平均值。

输入

有多组输入,每组输入的第一行为n(1<=n<=1e5),表示该数列的元素个数。
第二行为n个整数组成的无序数列

输出

每组样例输出一行,表示该无序数列的中位数。
若为偶数,请保留三位小数
若为奇数,直接输出

样例输入 Copy

5
5 3 2 1 4

样例输出 Copy

3

思路:数据量太大,Python 不能完全AC,请参考C++代码


问题 C: 第k大元素

题目描述

输入一个整数数组,请求出该数组的第k大元素。要求时间复杂度为O(n)。
 

输入

每组输入包括两行,第一行为k值;第二行为一个整数数组,两个数字之间用空格隔开。数组中元素个数小于1000。

输出

输出第k大元素的值,每个结果占一行

样例输入 Copy

2 
3 2 1 5 6 4

样例输出 Copy

5

思路:同第K小元素问题类似,对数组进行降序排列就行!

while True:
    try:
        k=int(input())
        nums= [int(i) for i in input().split()]
        nums.sort(reverse=True)
        for i in range(len(nums)):
            if i == k - 1:
                print(nums[i])
    except:
        break

问题 D: 数组合并

题目描述

编写一个程序,将两个有序数组合并成一个更大的有序数组,要求时间复杂度为O(n)。

输入

多组数据输入,每组输入包括两行,每行第一个数字为数组长度n,然后输入n个有序整数。

输出

输出合并后的数组(升序),每组输出用一个空行隔开。

样例输入 Copy

3 1 3 5
3 2 4 6
2 1 2
4 3 4 5 6

样例输出 Copy

1 2 3 4 5 6

1 2 3 4 5 6

思路:对给出的两个数组分别比较大小存放一个新的数组当中,当会出现两种情况,有一个数组没存放完或另一个数组没存放完。

def merge(a,b):
    re=[]
    i=j=0
    while len(a)>=i+1 and len(b)>=j+1:
        if a[i]<=b[j]:
            re.append(a[i])
            i+=1
        else:
            re.append(b[j])
            j+=1
    if len(a)>i:
        re+=a[i:]
    if len(b)>j:
        re+=b[j:]
    return re
while True:
    try:
        a=[int(i) for i in input().split()]
        b=[int(i) for i in input().split()]
        s1=a.pop(0)
        s2=b.pop(0)
        print(*merge(a,b))
        print()
    except:
        break

问题 E: 归并排序

题目描述

编写一个程序,使用分治策略实现二路归并排序(升序)。

输入

多组输入,每组第一个数字为数组长度,然后输入一个一维整型数组。

输出

输出排序之后(升序)的一维整型数组,每组输出占一行。

样例输入 Copy

6 1 8 6 5 3 4
5 12 42 2 5 8

样例输出 Copy

1 3 4 5 6 8
2 5 8 12 42

思路:可以分治法二路归并进行排序。也可以对数组直接排序so easy.


while True:
    try:
        a=[int(i) for i in input().split()]
        s1=a.pop(0)
        a.sort()
        print(*a)
    except:
        break

问题 F: 棋盘覆盖问题

题目描述

在一个n×n (n = 2k)个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为一特殊方格,且称该棋盘为一特殊棋盘。
在棋盘覆盖问题中,要用4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。

输入

多组测试用例,每组测试用例包括两部分,
第一部分为方格的宽度n,
第二部分则为方格,特殊方格为-1,其他方格为0。


输出

输出覆盖后的方案

样例输入 Copy

4
-1 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0

样例输出 Copy

-1 2 4 4
2 2 1 4
3 1 1 5
3 3 5 5

思路:先对二维数组判断出特殊方格的位置(dr,dc),然后按照递归的思想出,对每个方格进行判断递归,但对棋盘覆盖的数由四个if语句判断有关!

例如 

-1 2 4 4    -1 2 3 3
2 2 1 4  和  2 2 1 3
3 1 1 5      4 1 1 5
3 3 5 5      4 4 5 5

这两者的不同取决于if语句的先后顺序。

def chessBoard(tr,tc,dr,dc,size):
    if size == 1:
        return
    global tile
    global board
    tile += 1
    t = tile
    s = size//2
    if dr<tr+s and dc<tc+s:
        chessBoard(tr,tc,dr,dc,s)
    else:
        board[tr+s-1][tc+s-1] = t
        chessBoard(tr,tc,tr+s-1,tc+s-1,s)
    if dr >= tr + s and dc < tc + s:
        chessBoard(tr+s, tc, dr, dc, s)
    else:
        board[tr + s][tc + s - 1] = t
        chessBoard(tr+s, tc, tr + s, tc + s - 1, s)
    if dr < tr + s and dc >= tc + s:
        chessBoard(tr, tc+s, dr, dc, s)
    else:
        board[tr+s-1][tc+s] = t
        chessBoard(tr, tc+s, tr+s-1, tc+s, s)

    if dr >= tr + s and dc >= tc + s:
        chessBoard(tr+s, tc+s, dr, dc, s)
    else:
        board[tr + s][tc + s] = t
        chessBoard(tr+s, tc+s, tr+s, tc+s, s)

def show_chess(board):
    n = len(board)
    for i in range(n):
        for j in range(n):
            print(board[i][j], end=" ")
        print()
while True:
    try:
        tile = 0
        n=int(input())
        board=[[] for x in range(n)]
        for y in range(n):
            board[y]=list(map(int,input().split()))
        for i in range(n):
            for j in range(n):
                if board[i][j]==-1:
                    dr=i
                    dc=j
                    break
        chessBoard(0,0,dr,dc,n)
        show_chess(board)
    except:
        break

问题 G: Who's in the Middle

题目描述

FJ is surveying his herd to find the most average cow. He wants to know how much milk this 'median' cow gives: half of the cows give as much or more than the median; half give as much or less.

Given an odd number of cows N (1 <= N < 10,000) and their milk output (1..1,000,000), find the median amount of milk given such that at least half the cows give the same amount of milk or more and at least half give the same or less.

输入

* Line 1: A single integer N

* Lines 2..N+1: Each line contains a single integer that is the milk output of one cow.

输出

* Line 1: A single integer that is the median milk output.

样例输入 Copy

5
2
4
1
3
5

样例输出 Copy

3

提示

INPUT DETAILS: 
 Five cows with milk outputs of 1..5 
OUTPUT DETAILS: 
1 and 2 are below 3; 4 and 5 are above 3.

思路:很简单的题,对输入的数组进行排序,取数组中下标为n//2的数

while True:
    try:
        n=int(input())
        ls=[]
        for i in range(n):
            ls.append(int(input()))
        ls.sort()
        print(ls[n//2])
    except:
        break

问题 H: 和费马开个玩笑

题目描述

费马大定理:当n>2时,不定方程an+bn=cn没有正整数解。比如a3+b3=c3没有正整数解。我们来给他开个玩笑:把方程改成a3+b3=c3,这样就有解了,比如a=4, b=9, c=79时43+93=793。
输入两个整数x, y, 求满足x<=a,b,c<=y的整数解的个数。

输入

输入最多包含10组数据。每组数据包含两个整数x, y(1<=x,y<=108)。

输出

对于每组数据,输出解的个数。

样例输入 Copy

1 10
1 20
123 456789

样例输出 Copy

Case 1: 0
Case 2: 2
Case 3: 16

思路:其实这题不难,双重循环就可解决!由题意可以知道y的最大值不能超过1000,因为每组数据包含两个整数x, y(1<=x,y<=108)可知c最多8位数,和最后一位3就知道为9位数,而a,b又为立方。

ans=0
while True:
    try:
        x,y=map(int,input().split())
        res=0
        ans+=1
        for a in range(x,min(y+1,1001)):
            for b in range(x,a+1):
                n=a**3+b**3
                if n%10==3 and x<=n//10<=y:
                    if a!=b:
                        res+=2
                    else:
                        res+=1
        print(f"Case {ans}: {res}")
    except:
        break

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值