华为OD机试_2025 B卷_高矮个子排队(Python,100分)(附详细解题思路)

题目描述

现在有一队小朋友,他们高矮不同,我们以正整数数组表示这一队小朋友的身高,如数组{5,3,1,2,3}。

我们现在希望小朋友排队,以“高”“矮”“高”“矮”顺序排列,每一个“高”位置的小朋友要比相邻的位置高或者相等;每一个“矮”位置的小朋友要比相邻的位置矮或者相等;

要求小朋友们移动的距离和最小,第一个从“高”位开始排,输出最小移动距离即可。

例如,在示范小队{5,3,1,2,3}中,{5, 1, 3, 2, 3}是排序结果。

{5, 2, 3, 1, 3} 虽然也满足“高”“矮”“高”“矮”顺序排列,但小朋友们的移动距离大,所以不是最优结果。

移动距离的定义如下所示:

第二位小朋友移到第三位小朋友后面,移动距离为1,若移动到第四位小朋友后面,移动距离为2;

输入描述
排序前的小朋友,以英文空格的正整数:

4 3 5 7 8

注:小朋友<100个

输出描述
排序后的小朋友,以英文空格分割的正整数:4 3 7 5 8

备注:4(高)3(矮)7(高)5(矮)8(高), 输出结果为最小移动距离,只有5和7交换了位置,移动距离都是1。

用例

输入4 1 3 5 2
输出4 1 5 2 3
说明
输入1 1 1 1 1
输出1 1 1 1 1
说明相邻位置可以相等
输入xxx
输出[ ]
说明出现非法参数情况, 返回空数组。

小朋友排队问题:高矮交替排列的最小移动距离

核心解题思路

本题目要求将小朋友按照"高-矮-高-矮"的顺序排列,同时最小化移动距离。移动距离定义为小朋友位置变化的绝对值(如从位置2移动到位置3,移动距离为1)。核心解题思路如下:

关键观察

  1. 高矮交替规则

    • 偶数位置(0,2,4,…)是"高"位:当前身高 ≥ 下一个身高
    • 奇数位置(1,3,5,…)是"矮"位:当前身高 ≤ 下一个身高
    • 允许相等:相邻位置身高可以相等
  2. 最小移动距离策略

    • 只进行相邻元素交换,保证每次移动距离最小(移动距离=1)
    • 采用贪心算法:从左到右遍历,不满足条件时立即交换
    • 多轮处理:交换后可能影响前面位置,需要重新检查
  3. 算法流程

    graph TD
    A[输入身高数组] --> B{检查非法输入}
    B -->|非法| C[返回空数组]
    B -->|合法| D[初始化交换标志]
    D --> E[遍历数组]
    E --> F{当前位置是否满足条件?}
    F -->|是| G[继续下一个位置]
    F -->|否| H[交换相邻元素]
    H --> I[设置交换标志]
    I --> J[完成遍历?]
    J -->|是| K{是否发生交换?}
    K -->|是| D
    K -->|否| L[输出结果]
    

完整代码实现

def adjust_heights(heights):
    n = len(heights)
    # 创建交换标志,初始为True以进入循环
    swapped = True
    
    while swapped:
        swapped = False
        # 遍历除最后一个位置的所有元素
        for i in range(n - 1):
            if i % 2 == 0:  # 偶数位置:高位
                if heights[i] < heights[i + 1]:
                    # 交换相邻元素
                    heights[i], heights[i + 1] = heights[i + 1], heights[i]
                    swapped = True
            else:  # 奇数位置:矮位
                if heights[i] > heights[i + 1]:
                    # 交换相邻元素
                    heights[i], heights[i + 1] = heights[i + 1], heights[i]
                    swapped = True
    return heights

def main():
    try:
        # 读取输入
        data = input().split()
        # 检查空输入
        if not data:
            print("")
            return
        
        # 转换为整数并验证
        heights = []
        for s in data:
            if not s.isdigit():
                # 非法输入:包含非数字
                print("[ ]")
                return
            heights.append(int(s))
        
        # 特殊情况处理:全等或单个元素
        if len(heights) <= 1:
            print(" ".join(map(str, heights)))
            return
        
        # 调整身高顺序
        result = adjust_heights(heights)
        print(" ".join(map(str, result)))
    
    except Exception:
        # 异常处理
        print("[]")

if __name__ == "__main__":
    main()

算法原理解析

1. 高矮交替条件

if i % 2 == 0:  # 高位
    if heights[i] < heights[i + 1]:
        # 需要交换
else:  # 矮位
    if heights[i] > heights[i + 1]:
        # 需要交换
  • 高位要求:位置0,2,4,…的元素 ≥ 下一个元素
  • 矮位要求:位置1,3,5,…的元素 ≤ 下一个元素
  • 允许相等:不触发交换条件

2. 贪心交换策略

heights[i], heights[i + 1] = heights[i + 1], heights[i]
swapped = True
  • 只交换相邻元素:最小化单次移动距离(距离=1)
  • 设置交换标志:表示需要重新检查前面位置
  • 多轮处理while swapped确保完全满足条件

3. 输入验证

for s in data:
    if not s.isdigit():
        print("[]")
        return
  • 检查每个字符是否为数字
  • 包含非数字时输出空数组[]
  • 符合题目要求:非法输入返回空数组

4. 边界处理

  • 空输入:直接返回空字符串
  • 单元素数组:直接输出(无需处理)
  • 全等数组:自动满足条件,不进行交换

示例解析

示例1:输入4 1 3 5 2

  1. 初始状态[4, 1, 3, 5, 2]
  2. 第一轮遍历
    • 位置0(高位):4≥1 ✓
    • 位置1(矮位):1≤3 ✓
    • 位置2(高位):3≤5 ✗ → 交换 → [4,1,5,3,2]
    • 位置3(矮位):3≥2 ✗ → 交换 → [4,1,5,2,3]
  3. 第二轮遍历
    • 位置0:4≥1 ✓
    • 位置1:1≤5 ✓
    • 位置2:5≥2 ✓
    • 位置3:2≤3 ✓
  4. 输出4 1 5 2 3

示例2:输入1 1 1 1 1

  1. 初始状态[1,1,1,1,1]
  2. 遍历检查
    • 所有位置都满足条件(1≥1 且 1≤1)
  3. 不进行任何交换
  4. 输出1 1 1 1 1

示例3:输入xxx

  1. 输入验证:包含非数字字符x
  2. 直接输出[]

示例4:输入4 3 5 7 8

  1. 初始状态[4,3,5,7,8]
  2. 第一轮遍历
    • 位置0:4≥3 ✓
    • 位置1:3≤5 ✓
    • 位置2:5≤7 ✗ → 交换 → [4,3,7,5,8]
    • 位置3:5≤8 ✓
  3. 第二轮遍历
    • 位置0:4≥3 ✓
    • 位置1:3≤7 ✓
    • 位置2:7≥5 ✓
    • 位置3:5≤8 ✓
  4. 输出4 3 7 5 8

总结与拓展

关键知识点

  1. 贪心算法应用:通过局部最优(相邻交换)实现全局最优
  2. 循环验证:多轮处理确保完全满足条件
  3. 边界处理:非法输入和特殊情况的处理
  4. 移动距离最小化:只进行相邻交换策略

拓展思考

  1. 优化方向:如何减少交换次数?
    • 记录交换位置,下一轮从该位置开始
  2. 非相邻交换:允许非相邻交换是否能减少总移动距离?
    • 分析:非相邻交换的移动距离更大,不推荐
  3. 双向处理:从左到右+从右到左交替处理
    • 可能减少循环轮次
  4. 动态规划:O(n²)时间复杂度,记录最小移动路径
    • 适用于更大数据集
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值