HNUCM-2022年秋季学期《算法分析与设计》练习7

目录

问题 A: 整数奇偶排序

问题 B: 随机化快速排序

问题 C: 数组合并

问题 D: 第k小元素问题

问题 E: 第k大元素

问题 F: 找中位数

问题 G: Fy's dota2

问题 H: Who's in the Middle


问题 A: 整数奇偶排序

题目描述:

输入10个整数,彼此以空格分隔。重新排序以后输出(也按空格分隔),要求:
1.先输出其中的奇数,并按从大到小排列;
2.然后输出其中的偶数,并按从小到大排列。

输入:

任意排序的10个整数(0~100),彼此以空格分隔。

输出:

可能有多组测试数据,对于每组数据,按照要求排序后输出,由空格分隔。

while True:
    try:
        nums = [int(i) for i in input().split()]
        ji = [i for i in nums if i % 2 == 1]
        ou = [i for i in nums if i % 2 == 0]
        ji.sort(reverse=True)
        ou.sort()
        str1 = ''
        for j in ji:
            str1 += f"{j} "
        for o in ou:
            str1 += f"{o} "
        print(str1.strip())
    except:
        break

问题 B: 随机化快速排序

题目描述:

使用Java或C++等语言中内置的随机函数实现随机化快速排序,在数组中随机选择一个元素作为分区的主元(Pivot)。

输入:
多组样例输入,每组由一个一维整型数组组成。

输出:

随机化快速排序之后的一维整型数组(升序排列)。

思路:上次写的很复杂,在老师的教学后,发现其实很简单,就是比普通的快速排序多一个随机选择和交换。

import random


def quick(start: int, end: int):
    if start <= end:
        mid = random.randint(start, end)  # 基准的下标
        nums[start], nums[mid] = nums[mid], nums[start]  # 交换基准
        i, j = start, end
        res = nums[start]  # 选择基准
        while True:
            while j > i and nums[j] >= res:
                j -= 1
            while i < j and nums[i] <= res:
                i += 1
            if i < j:
                nums[i], nums[j] = nums[j], nums[i]
            else:
                nums[start], nums[j] = nums[j], nums[start]
                break
        quick(start, j - 1)
        quick(j + 1, end)
    return


while True:
    try:
        nums = [int(i) for i in input().split()]
        n = nums.pop(0)
        quick(0, n - 1)
        for i in range(n):
            print("", nums[i], end='') if i != 0 else print(nums[i], end='')
        print()
    except:
        break

问题 C: 数组合并

题目描述:

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

输入:

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

输出:

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

思路:遍历两个列表即可,时间复杂度为O(n)(2n)。

def merge_sort(a, b):
    ret = []
    i = j = 0
    while len(a) >= i + 1 and len(b) >= j + 1:
        if a[i] <= b[j]:
            ret.append(a[i])
            i += 1
        else:
            ret.append(b[j])
            j += 1
    if len(a) > i:
        ret += a[i:]
    if len(b) > j:
        ret += b[j:]
    return ret


while True:
    try:
        num1, num2 = [int(i) for i in input().split()], [int(i) for i in input().split()]
        n1, n2 = num1.pop(0), num2.pop(0)
        str1 = ""
        for num in merge_sort(num1, num2):
            str1 += f"{num} "
        print(f"{str1}\n")
    except:
        break

问题 D: 第k小元素问题

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

输入:

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

输入:

输出第k小元素的值。

每日一偷鸡:“当看见元素个数小于1000的时候,我就明白,偷鸡的机会来了。”——当事人。

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

思路:就是老师上课讲的,对随机快速排序的一种改版使用。

import random


def quick(start: int, end: int):
    if 0 < start <= end:
        mid = random.randint(start, end)  # 基准的下标
        nums[start], nums[mid] = nums[mid], nums[start]  # 交换基准
        i, j = start, end
        res = nums[start]  # 选择基准
        while True:
            while j > i and nums[j] >= res:
                j -= 1
            while i < j and nums[i] <= res:
                i += 1
            if i < j:
                nums[i], nums[j] = nums[j], nums[i]
            else:
                nums[start], nums[j] = nums[j], nums[start]
                break
        if j == k:
            return nums[k]
        elif j < k:
            return quick(j + 1, end)
        else:
            return quick(start, j - 1)
    return -1


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

问题 E: 第k大元素

题目描述:

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

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

输出:

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

偷鸡:

while True:
    try:
        k, nums = int(input()), [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题的代码改下排序就行。

import random


def quick(start: int, end: int):
    if 0 < start <= end:
        mid = random.randint(start, end)  # 基准的下标
        nums[start], nums[mid] = nums[mid], nums[start]  # 交换基准
        i, j = start, end
        res = nums[start]  # 选择基准
        while True:
            while j > i and nums[j] <= res:
                j -= 1
            while i < j and nums[i] >= res:
                i += 1
            if i < j:
                nums[i], nums[j] = nums[j], nums[i]
            else:
                nums[start], nums[j] = nums[j], nums[start]
                break
        if j == k:
            return nums[k]
        elif j < k:
            return quick(j + 1, end)
        else:
            return quick(start, j - 1)
    return -1


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

问题 F: 找中位数

题目描述:

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

输入:

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

输出:

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

偷鸡:题目不难,但是数据量较大,不适合用python写,以下是C++代码。

#include<bits/stdc++.h>
using namespace std;
int nums[100005];
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0;i<n;i++)
            scanf("%d",&nums[i]);
        sort(nums, nums+n);
        int index = n/2;
        if(n%2==1)printf("%d\n", nums[index]);
        else printf("%.3f\n", (nums[index-1] + nums[index])*1.0/2.0);
    }
}

问题 G: Fy's dota2

题目描述:

Fy 觉得自己玩 cf,lol这种高端游戏已经够厉害了,于是他决定去玩dota2。结果 fy 的鼠标右键坏了,所以他就等到 2500 买了把闪烁匕首,用跳刀前进,准备去送泉水。但是 fy 一次最多前进 k 的距离,泉水离 fy 现在的距离是 n。

Fy 想知道他到泉水的方案数。

输入:

第一行 2 个整数:k,n 
1<=n<=2^31-1,1<=k<=10 

输出:

一行 1 个整数:代表答案对 7777777 取膜的结果 

C++代码:

 #include <bits/stdc++.h>
 using namespace std;
 #define LL long long
 
 struct Martix
 {
     LL a[12][12];
     Martix friend operator * (Martix x, Martix y)
         {
             Martix ans;
             memset(ans.a, 0, sizeof(ans));
             for(int i = 1; i <= 11; ++ i)
                 for(int j = 1; j <= 11; ++ j)
                     for(int k = 1; k <= 11; ++ k)
                         ans.a[i][j] = (ans.a[i][j] + (x.a[i][k] * y.a[k][j]) % 7777777) % 7777777; 
             return ans;
         }
 
     Martix friend operator % (Martix x, int m)
         {
             for(int i = 1; i<= 11; ++ i)
                 for(int j = 1; j <= 11; ++ j)
                     x.a[i][j] = x.a[i][j] % m;
             return x;
         }
 };
 int m, n;
 LL f[15], sum[15];
 Martix ksm(Martix x, LL b, LL mod)
     {
         Martix ret;
         memset(ret.a, 0, sizeof(ret.a));
         for(int i = 1; i <= m; ++ i)    ret.a[1][i] = f[i];
         for(;b; b >>= 1, x = (x * x) % mod)
             if(b & 1)    ret = (ret * x) % mod;
         return ret;
     }
 
 int main()
 {
 //    freopen("fyfy.in","r",stdin);
 //    freopen("fyfy.out","w",stdout);
     LL ans = 0;
     Martix zy;
     memset(zy.a, 0, sizeof(zy.a));
     scanf("%d%d", &m, &n);
     if(n > m)
     {
         for(int i = 1; i <= m; ++ i) zy.a[i][m] = 1, f[i] = 1;
         for(int i = 2; i <= m; ++ i)    zy.a[i][i - 1] = 1;
         for(int i = 1; i <= m; ++ i)
             for(int j = 1; j < i; ++ j)
                 f[i] = f[i] + f[j];
         zy = ksm(zy, n - 1, 7777777);
 //        for(int i = 1; i <=m; ++ i)
 //            ans = (ans + ((long long)f[i] * zy.a[i][1]) % 7777777) % 7777777;
         printf("%lld\n", zy.a[1][1]);
     }
     else
     {
         for(int i = 1; i <= n; ++ i)    f[i] = sum[i - 1] + 1, sum[i] = sum[i - 1] + f[i];
         printf("%lld\n", f[n]);
     }
     return 0;
 }

问题 H: 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.

while True:
    try:
        n, cows, cnt = int(input()), [], 0
        while n > cnt:
            cnt, milk = cnt + 1, int(input())
            cows.append(milk)
        cows.sort()
        print(cows[n//2])
    except:
        break
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值