华为OD机试真题C卷-篇5

生成Huffman树

  • 给定一个数值数组weights,每个值代表二叉树叶子节点的权值(>=1);
  • 根据权值数组,生成哈夫曼树,并中序遍历输出;
  • 左节点权值<= 右节点权值,根节点权值为左右节点权值之和;
  • 左右节点权值相同时,左子树高度<=右子树;
    在这里插入图片描述
    输入描述:
    第一行输入数组长度n;
    第二行输入权值,以空格分隔;
    输出描述:
    哈夫曼树的中序遍历序列,以空格分隔;

示例1
输入:
5
5 15 40 30 10
输出:
40 100 30 60 15 30 5 15 10
==思路:==建立哈夫曼树的过程

  • 以每个权值创建一个节点(只有一个树根的二叉树),放入nodes_list,并按照权值从小到大排序;
  • 取出权值最小的两个节点,进行合并,根节点权值为左右子节点的权值之和
    • 设置根节点的左子树、右子树
    • 当左右子树(根节点)权值相同时,对比两者的树高,高的子树作为右子树;
    • 统计子树的高度 max(h_left, h_right),h_left为每次取左子树;
  • 将合并后的root根节点放入nodes_list,继续以上步骤,直到nodes_list中只有一个根节点;

# 中序遍历结果
result = []
# 输入n
n = int(input().strip())
weights = [int(x) for x in input().strip().split()]
 

class TreeNode:
    def __init__(self, left, right, weight, height):
        self.left = left
        self.right = right
        self.weight = weight
        self.height = height
 

# 中序遍历
def dfs(node):
	# 中序遍历左子树
    if node.left is not None:
        dfs(node.left)
    # 中间处理根
    result.append(node.weight)
    # 中序遍历右子树
    if node.right is not None:
        dfs(node.right)
        
    
# 建立哈夫曼树
nodes_list = []
for i in range(n):
    nodes_list.append(TreeNode(None, None, weights[i], 1))

# 比较树高
def comp(o1, o2):
    if(o1.weight == o2.weight): # 权值相等
        if o1.height > o2.height:
            return 1
        else:
            return -1
    
    if o1.weight > o2.weight:
        return 1
    else:
        return -1


while True:
    if len(nodes_list) == 1:
        break
    else :
        nodes_list = sorted(nodes_list, key=lambda i:i.weight)
        node1 = nodes_list.pop(0)
        node2 = nodes_list.pop(0)
        root = TreeNode(None, None, node1.weight + node2.weight, max(node1.height, node2.height) + 1)
        if comp(node1, node2) == 1:
        	root.right = node1
        	root.left = node2
        else:
        	root.right = node2
        	root.left = node1
        nodes_list.append(root)
    
 
 
dfs(nodes_list[0]) # 传入树根,中序遍历
# 输出字符串
output_str = ""
for i in range(len(result)):
    output_str += str(result[i])
    if(i!=len(result)-1):
        output_str+=" "
print(output_str)

 

小朋友来自多少小区

  • 每个小朋友报出与自己同一个小区的人数,存入数组garden中;
  • 计算至少有几个小区?多少小朋友?
    输入描述:
    输入garden数组,如2 2 3, 即第一个小朋友报出有2个小朋友跟自己同一个小区,第二个小朋友同样报出2个,依次类推; garden数组长度最大为999;
    输出描述:
    至少的小区数,小朋友数

示例1
输入:
2 2 3
输出:
2,7

示例2
输入:
2 2 2 2 2 3 3
输出:
3,10

思路:

  • 贪心算法,依次遍历,让尽可能多的小朋友在同一个小区;
    • garden 升序排序;
    • 初始化 小区数areas=1, friend_nums = garden[0]+1,dist= garden[0]
    • 从i=1开始遍历garden,for i in range(1, len(garden)): 如果当前报数与前一个报数相同,则判断能否算入同一个小区;
      • 是,则dist-=1,继续下一次遍历;
      • 否,则areas += 1, friend_nums += garden[i] +1, dist=garden[i]
    • 输出areas,friend_nums


class GardenNum:
    def solution(self, garden):
        # 排序
        garden.sort()
        # 初始化
        areas = 1
        friend_nums = garden[0] + 1
        dist = garden[0]
        for i in range(1, len(garden)):
            if garden[i] == garden[i-1]: # 可能是同一个小区
                if dist > 0:
                    # 算入同一个小区
                    dist -= 1
                else:
                    areas += 1 #
                    friend_nums += garden[i] + 1
                    dist = garden[i]

            else:
                # 报数与前一个不同,肯定不是同一个小区
                areas += 1  #
                friend_nums += garden[i] + 1
                dist = garden[i]

        print(areas, end=",")
        print(friend_nums)


if __name__ == '__main__':
    garden_num = GardenNum()
    while True:
        try:
            garden = list(map(int, input().strip().split()))
            garden_num.solution(garden)
        except KeyboardInterrupt:
            break

其他基于索引的实现:

nums = [int(x) for x in input().split(" ")]
#index为报告的结果,zones[index]为报告相同结果的总人数
zones = [0 for x in range(1000)]
count = 0
 
i=0
while(True):
  if(i>=len(nums)):
    break
  else:
    zones[nums[i]]+=1
  
  i+=1
 
 
for j in range(1000):
    if (zones[j] <= 0):
      continue
    else:
      total = math.ceil(zones[j] / (j+1));
      count += total * (j+1);
print(count);

 

堆内存申请

在这里插入图片描述
在这里插入图片描述

 
 
n = int(input())
memorys = []
while (True) :
    try:
        nums = [int(x) for x in input().split(" ")]
        memorys.append([nums[0], nums[0]+nums[1]- 1])
    except:
        break
 
memorys.sort()
length = len(memorys)
flag = 0
for i in range(length):
    x = memorys[i][0]
    y = memorys[i][1]
    if (not ((x >= 0 and y >= 0 and x < 100 and y < 100 and x <= y) and 
        (not (i > 0 and x <= memorys[i-1][1])))) :
        flag = 1  
        break  
    
 
 
if (flag!=1) :
    offset = -1
    max_distance = 100
    start = memorys[0][0]
    if (start >= n and start < max_distance + n) :
        offset = 0
        max_distance = start - n
    
    i=1
    while(True):
        if(i>=length):
            break
        else :
            current = memorys[i][0]
            before = memorys[i-1][1]
            if (current - before > n):
                if(current - before < max_distance + n) :
                    offset = before + 1
                    max_distance = current - before - n
                    break
        i+=1
 
    end = memorys[length - 1][1]
    if (end<=99-n and end > 99-n-max_distance) :
        offset = end + 1
    
    print(offset)
else:
    print(-1)

 

跳格子3

在这里插入图片描述


 
n =int(input())
nums = [int(x) for x in input().split(" ")]
k = int(input())
queue = [[0 for i in range(2)] for j in range(n)]
cache =[0 for i in range(n)]
cache[0] = nums[0]
queue[0][0] = 0
queue[0][1] = cache[0]
index1 = 0
index2 = 1
 
i=1
while(True):
    if(i>=n):
        break
    else :
        while(index1<index2):
            if(queue[index1][0] < i - k):
                index1 +=1
            else :
                break
            
        
        cache[i] = nums[i] + queue[index1][1]
 
        while(index1<index2):
            if(queue[index1][1] <= cache[i]):
                index1 +=1
            else :
                break
        queue[index2][0] = i
        queue[index2][1] = cache[i]
        index2+=1
    
    i+=1
 
print(cache[n - 1])

 

测试用例执行计划

  • 某产品有n个特性,每个特性有一个优先级;
  • 设计m个测试用例,每个测试用例对应一个特性的集合,测试用例的优先级为其对应特性的优先级之和;
  • 测试用例按照优先级大的先执行,优先级相同则ID小的先执行;
    输入描述:
    第一行输入n、m;
    后续n行输入特性 ID=1到 ID=n的优先级;
    后续m行输入测试用例ID=1到ID=m 对应的特性ID列表
    输出描述:
    按照执行顺序,输出测试用例的ID,每行一个ID;

示例1
输入:
5 4
1
1
2
3
5
1 2 3
1 4
3 4 5
2 3 4
输出:
3
4
1
2

示例2
输入:
3 3
3
1
5
1 2 3
1 2 3
1 2 3
输出:
1
2
3

思路:
简单排序问题

 
class TestCase:
    def solution(self, test_case_pri_list, m):
        idx_list = [i for i in range(m)]

        # 值相同时,索引保持从小到大
        idx_list.sort(key=lambda i: test_case_pri_list[i], reverse=True)
        for idx in idx_list:
            print(idx+1)


if __name__ == '__main__':
    test_case = TestCase()
    while True:
        try:
            n, m = list(map(int, input().strip().split()))
            feature_pri_list = []
            test_case_pri_list = []
            for i in range(n):
                feature_pri_list.append(int(input().strip()))
            for i in range(m):
                val = [feature_pri_list[j-1] for j in list(map(int, input().strip().split()))]
                test_case_pri_list.append(sum(val))
            test_case.solution(test_case_pri_list, m)
        except KeyboardInterrupt:
            break

 

贪吃的猴子

  • 一只猴子获取香蕉,只能从数组(元素为香蕉数)的头部或者尾部开始获取;
  • 最多只能取n次;
  • 求最多获取的香蕉数;
    输入描述:
    第一行输入数组长度m;
    第二行输入数组的数据;
    第三行为获取次数n;
    输出描述:
    获取的最大数值

示例1
输入:
7
1 2 2 7 3 6 1
3
输出:
10

示例2
输入:
3
1 2 3
3
输出:
6

示例3
输入:
4
4 2 2 3
2
输出:
7

思路:

  • 双指针,先从开头依次取n次,并求和total_bra;
  • 依次从开头开始的第n次,减少一次,从末尾取,求和并与total_bra比较,取最大值;
  • 依次类推
 
n = int(input())
nums = [int(x) for x in input().split(" ")]
count = int(input())
temp_sum = 0
for i in range(count):
    temp_sum += nums[i]

result = temp_sum
left = count - 1
right = n - 1

while (True):
    if (left < 0):
        break
    else:
        temp_sum += nums[right] - nums[left] # 减去左边的取值,加上当前末尾的取值
        if (temp_sum > result):
            result = temp_sum
        right -= 1
        left -= 1
print(result)

 

小扇和小船的数字游戏

在这里插入图片描述

 
def getBinaryOneCount(num):
    count = 0
    while(True):
        if(num <=0):
            break
        else :
            count += num % 2
            num = int(num/2)
    return count
 
 
n = int(input())
m = n+1
while(True):
    if (getBinaryOneCount(m) == getBinaryOneCount(n)):
        break
    m+=1
print(m)

 

幸存数之和

  • nums为正整数数组,jump为跳数,left为幸存数量
  • 运算过程:从索引为0开始向后跳,中间跳过jump个数字,命中索引为jump+1的数字,该数被敲出,并从该点起跳,依次类推,直到nums数组中幸存left个数,然后返回幸存数之和;
  • 起点、命中点之间间隔jump个数字,已被敲出的数字不计入在内;
  • 跳到数组末尾时,从头开始(循环查找)
  • 若起始时, left >len(nums), 则无需跳数处理,直接计算和;
    输入描述:
    第一行输入nums数组
    第二行输入jump跳数
    第三行输入left幸存数
    输出描述:
    输出幸存数之和

示例1
输入:
1,2,3,4,5,6,7,8,9
4
3
输出:
13
说明:
依次删除6 2 8 5 4 7

 
def sumOfLeft(nums, jump, left) :
    size = len(nums)
    start = 0
    while True:
        if len(nums) <= left:
            break
        else :
            start += jump + 1
            start = start % len(nums)
            nums.pop(start)
            start -=1 
    remain_sum = 0
    for i in range(len(nums)):
        remain_sum +=nums[i]
    return remain_sum

 

CPU算力分配

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

 
params = [int(x) for x in input().split(" ")]
count1 = params[0]
count2 = params[1]
nums1 = [int(x) for x in input().split(" ")]
sum1 = sum(nums1)
nums2 = [int(x) for x in input().split(" ")]
sum2 = sum(nums2)
num2_map = {}
for key in nums2:
    num2_map[key] = 1
 
nums1.sort()
i=0
while(True):
    if(i>=count1):
        break
    else :
        target = nums1[i] - int((sum1-sum2)/2)
        if (target in num2_map) :
            print(str(nums1[i]) + " " + str(target))
            break
        
    
    i+=1
 

 

亲子游戏

  • 在一个二维矩阵(n*n)的格子地图上,宝宝和妈妈抽签决定各自的位置,每个格子有不同数量的糖果,部分格子有障碍物;
  • 游戏规则,妈妈必须在最短的时间(每次走一步)到达宝宝的位置,路上的糖果都可以拿走,不能走障碍物的格子,只能上下左右的走;
  • 妈妈在最短到达宝宝位置的时间内最多拿到多少糖果。
    输入描述:
    第一行输入n;
    后续n行,每行有n个值,-3表示妈妈,-2表示宝宝,-1表示障碍物,>=0表示糖果数,0没有糖果,但可以通过;
    输出描述:
    妈妈在最短到达宝宝位置的时间内最多拿到多少糖果,地图最大50*50;
    若无法到达宝宝位置,则输出-1

示例1
输入:
4
3 2 1 -3
1 -1 1 1
1 1 -1 2
-2 1 2 3
输出:
9

示例2
输入:
4
3 2 1 -3
-1 -1 1 1
1 1 -1 2
-2 1 -1 3
输出:
-1

思路:

  • BFS/DFS
  • 先找最短路径(最少步子),在最短路径的情况下,再找最多糖果数;
  • 两次BFS

class MBGame:
    def solution(self, n, arr):
        self.visited = [[0 for j in range(n)] for i in range(n)]

        # 找妈妈的位置
        self.mother_pos = self.find_pos(n, arr, -3)

        # 找baby的位置
        self.baby_pos = self.find_pos(n, arr, -2)

        # 寻找最短路径(广度优先)
        steps = self.BFS(n)
        print("最短路径:", steps)

        # 计算在最短路径下的最大糖果数(走 steps 步)
        candy_arr = [[-1 for i in range(n)] for j in range(n)] # 不能用visited控制访问过程
        candy_arr[self.mother_pos[0]][self.mother_pos[1]] = 0 # 起始位置糖果数为0
        # 再次广度优先
        queue = [self.mother_pos]
        while True:
            if steps <= 0:
                break

            # 出队
            size = len(queue)
            for i in range(size):
                cur_pos = queue.pop(0)
                # 从当前格子走四个方向
                x, y = cur_pos
                directions = [(x, y + 1), (x, y - 1), (x - 1, y), (x + 1, y)]
                for new_x, new_y in directions:
                    # 新位置有效、不为-1、未走过,则可以走
                    if 0 <= new_x < n and 0 <= new_y < n and arr[new_x][new_y] != -1:
                        if candy_arr[new_x][new_y] == -1:
                            # 入队
                            queue.append((new_x, new_y))
                        # 更新新位置的糖果数
                        if arr[new_x][new_y] != -2: # 没到终点
                            candy_arr[new_x][new_y] = max(candy_arr[new_x][new_y],
                                                          candy_arr[x][y] + arr[new_x][new_y])
                        else: # 可以用2x2的 矩阵演示说明
                            candy_arr[new_x][new_y] = max(candy_arr[new_x][new_y],
                                                          candy_arr[x][y])
            steps -= 1
        for i in range(n):
            print("candy_arr:", candy_arr[i]) # 终点位置即为最大糖果数
        print(candy_arr[self.baby_pos[0]][self.baby_pos[1]])

    def BFS(self, n):
        # 起始点入队
        queue = []
        queue.append(self.mother_pos)

        # flag 标识是否能走到终点
        flag = False
        # 走的步子数
        steps = 0
        # 循环出队
        while True:
            size = len(queue)
            if size <= 0: # 判断队列是否为空
                break
            for i in range(size): # 当前层级的所有的位置,作为起始点(同时向外层走一步)
                start_pos = queue.pop(0)
                # 判断当前位置是否为终止位置
                x, y = start_pos
                if arr[x][y] == -2:
                    flag = True  # 走到终点,直接结束
                    break
                else:
                    # 从当前位置,开始走四个方向
                    directions = [(x, y+1), (x, y-1), (x-1, y), (x+1, y)]
                    for new_x, new_y in directions:
                        # 新位置有效、不为-1、未走过,则可以走
                        if 0 <= new_x < n and 0 <= new_y < n and arr[new_x][new_y] != -1 and \
                                self.visited[new_x][new_y] == 0:
                            self.visited[new_x][new_y] = 1 # 表示已走过
                            # 新位置入队
                            queue.append((new_x, new_y))
            if flag: # 走到终点,则提前终止外层循环
                break
            # 走一步
            steps += 1

        if not flag: # 无法到达终点
            return -1
        # 到达终点
        return steps # 第一个搜索到达的路径,一定是最短路径

    def find_pos(self, n, arr, val):
        for i in range(n):
            for j in range(n):
                if arr[i][j] == val:
                    m_pos = (i, j)
                    return m_pos


if __name__ == '__main__':
    mb_game = MBGame()
    # 3 2 1 -3
    # 1 -1 1 1
    # 1 1 -1 2
    # -2 1 2 3
    while True:
        try:
            n = int(input().strip())
            arr = []
            for i in range(n):
                arr.append(list(map(int, input().strip().split())))

            mb_game.solution(n, arr)
        except KeyboardInterrupt:
            break

 

传递悄悄话

  • 给定一个二叉树,节点采用顺序存储,如 i=0 表示根节点,2i + 1 表示左子树根,2i + 2 表示右子树根;
  • 每个节点站一个人,节点数值表示由父节点到该节点传递消息需要的时间;
  • 输出从根节点,将消息传递给所有的人需消耗的时间;
    输入描述:
    0 9 20 -1 -1 15 17 -1 -1 -1 -1 3 2 ;节点的顺序存储;-1表示空节点
    输出描述:
    所有的人都收到消息所消耗的时间 38

示例1
输入:
0 9 20 -1 -1 15 17 -1 -1 -1 -1 3 2
输出:
38

示例2
输入:
0
输出:
0

示例3
输入:
0 9
输出:
9

说明:
还原出二叉树如下
在这里插入图片描述

思路:

  • 求二叉树的最大路径和;
  • BFS + 队列
class MaxPathSum:
    def solution(self, alist):
        # 广度优先入队
        queue = []
        queue.append((0, 0)) # 根节点入队  结构为-->(节点索引, 根节点到当前节点的路径和)
        result = 0 # 最大路径和
        while True:
            if len(queue) <= 0:
                break
            root_node = queue.pop(0)
            if self.is_leaf(root_node, alist):
                print("leaf:", root_node)
                result = max(result, root_node[1])
            else:
                # 继续找左子节点、右子节点
                left_node_idx = 2 * root_node[0] + 1
                if left_node_idx < len(alist) and alist[left_node_idx] != -1:
                    left_node_path_sum = alist[left_node_idx] + root_node[1]
                    # 新节点入队
                    queue.append((left_node_idx, left_node_path_sum))
                right_node_idx = 2 * root_node[0] + 2
                if right_node_idx < len(alist) and alist[right_node_idx] != -1:
                    right_node_path_sum = alist[right_node_idx] + root_node[1]
                    queue.append((right_node_idx, right_node_path_sum))

        print(result)

    def is_leaf(self, node, alist):
        node_idx = node[0]
        left_idx = 2 * node_idx + 1
        right_idx = 2 * node_idx + 2
        # 索引的有效性
        if left_idx >= len(alist):
            return True
        elif left_idx < len(alist) and right_idx >= len(alist):
            if alist[left_idx] == -1:
                return True
            return False
        else:
            # 索引均有效
            if alist[left_idx] != -1 or alist[right_idx] != -1:
                return False
            return True


if __name__ == '__main__':
    max_path_sum = MaxPathSum()
    while True:
        try:
            alist = list(map(int, input().strip().split()))
            max_path_sum.solution(alist)
        except KeyboardInterrupt:
            break

 

  • 10
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
华为OD机试-2023真题主要考察了以下几个方面的知识点: 1. 数据结构与算法:题目涉及了常见的数据结构和算法,如数组、链表、树、图、排序、搜索等。要求考生熟悉这些数据结构的基本操作和常用算法的实现方法。 2. 编程语言:题目要求使用C++或Java语言完成编程任务,要求考生熟悉相应语言的语法和常用的库函数使用方法。 3. 网络通信:题目涉及了网络通信相关的知识点,如TCP/IP协议、HTTP协议、socket编程等。要求考生了解网络通信的基本概念和实现方式。 4. 操作系统:题目要求考生熟悉操作系统相关的知识,如进程管理、内存管理、文件系统等。要求考生了解操作系统的基本功能和实现原理。 5. 数据库:题目涉及了数据库相关的知识点,如SQL语句的编写、数据库的设计和优化等。要求考生具备数据库的基本操作和设计能力。 6. 设计模式:题目要求考生能够根据给定的需求设计相应的对象和类,并且符合设计模式的原则。要求考生熟悉常见的设计模式和其应用场景。 7. 系统设计与架构:题目要求考生从整体上设计和实现一个系统,并考虑系统的性能、可扩展性等因素。要求考生了解系统设计的基本原则和方法。 以上是华为OD机试-2023真题的一些考点分类。考生在复习备考时,可以根据这些考点有针对性地进行学习和练习,提升自己的应试能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

laufing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值