华为(9)输入n个整数,输出其中最小的k个

本文介绍了一个使用C++实现的算法,该算法能够从输入的整数数组中找出最小的K个数,并将这些数输出。通过插入排序的方式对数组进行部分排序,仅保留前K个元素,从而达到高效查找的目的。
#include <iostream>
using namespace std;
bool GetMinK(unsigned int uiInputNum, int * pInputArray, unsigned int uiK, int * pOutputArray)
{
    if(NULL==pInputArray || NULL==pOutputArray)
    {
        return false;
    }
    for(int j=1;j<int(uiInputNum);++j)
    {
        int key=pInputArray[j];
        int i=j-1;
        while(i>=0 && key<pInputArray[i])
        {
            pInputArray[i+1]=pInputArray[i];
            --i;
        }
        pInputArray[i+1]=key;
    }
    for(unsigned int i=0;i<uiK;++i)
    {
        pOutputArray[i]=pInputArray[i];
        if(i!=uiK-1)
            cout<<pOutputArray[i]<<' ';
        else
            cout<<pOutputArray[i];
    }
    return true;
}
int main()
{
    unsigned int inputn=0;
    unsigned int mink=0;
    cin>>inputn>>mink;
    int *pInputArray=new int[inputn];
    for(unsigned int i=0;i<inputn;++i)
    {
        cin>>pInputArray[i];
    }
    int *pOutputArray=new int[mink];
    GetMinK(inputn,pInputArray,mink,pOutputArray);
    return 0;
}

### 整数最小和问题解决方案 #### 背景分析 该问题是典型的贪心算法应用案例,目标是从两个数组 `array1` 和 `array2` 中分别选取若干对元素,使这些配对的和尽可能小。通过合理排序与优先队列的选择策略可以有效降低时间复杂度。 --- #### 方法概述 一种高效的解决方法是基于 **堆(Heap)数据结构** 的实现方式。具体思路如下: 1. 将其中一个数组按升序排列。 2. 使用一个小顶堆来存储当前可能的最小和及其对应的索引位置。 3. 每次从堆中弹出最小值,并将其扩展到下一个候选值,直到找到所需的前 K 个最小和为止。 此方法的时间复杂度为 \( O(K \log n) \),相较于暴力枚举法显著优化[^2]。 以下是具体的代码实现示例: --- #### Python 实现 ```python import heapq def find_k_smallest_pairs(array1, array2, k): result = [] if not array1 or not array2: return result heap = [(array1[0] + array2[0], 0, 0)] # 初始化堆 (sum, i, j) visited = set((0, 0)) while len(result) < k and heap: sum_val, i, j = heapq.heappop(heap) result.append([array1[i], array2[j]]) # 扩展新的候选项 if i + 1 < len(array1) and (i + 1, j) not in visited: heapq.heappush(heap, (array1[i + 1] + array2[j], i + 1, j)) visited.add((i + 1, j)) if j + 1 < len(array2) and (i, j + 1) not in visited: heapq.heappush(heap, (array1[i] + array2[j + 1], i, j + 1)) visited.add((i, j + 1)) return result # 测试用例 if __name__ == "__main__": array1 = [1, 7, 11] array2 = [2, 4, 6] k = 3 pairs = find_k_smallest_pairs(array1, array2, k) total_sum = sum(a + b for a, b in pairs) print(f"最小和的 {k} 对元素为: {pairs}") print(f"总和为: {total_sum}") ``` 上述代码实现了利用堆求解最小和的方法。对于给定测试用例 `[1, 7, 11]`, `[2, 4, 6]` 和 `k=3`,程序会返回前三对最小和的组合并计算其总和[^1]。 --- #### Java 实现 ```java import java.util.*; public class SmallestSumPairs { public static List<List<Integer>> findKSmallestPairs(int[] nums1, int[] nums2, int k) { PriorityQueue<int[]> minHeap = new PriorityQueue<>((a, b) -> (a[0] - b[0])); List<List<Integer>> result = new ArrayList<>(); if (nums1.length == 0 || nums2.length == 0 || k == 0) { return result; } Set<String> visited = new HashSet<>(); minHeap.offer(new int[]{nums1[0] + nums2[0], 0, 0}); visited.add("0,0"); while (!minHeap.isEmpty() && result.size() < k) { int[] current = minHeap.poll(); int sum = current[0]; int i = current[1]; int j = current[2]; result.add(Arrays.asList(nums1[i], nums2[j])); if (i + 1 < nums1.length && !visited.contains((i + 1) + "," + j)) { minHeap.offer(new int[]{nums1[i + 1] + nums2[j], i + 1, j}); visited.add((i + 1) + "," + j); } if (j + 1 < nums2.length && !visited.contains(i + "," + (j + 1))) { minHeap.offer(new int[]{nums1[i] + nums2[j + 1], i, j + 1}); visited.add(i + "," + (j + 1)); } } return result; } public static void main(String[] args) { int[] nums1 = {1, 7, 11}; int[] nums2 = {2, 4, 6}; int k = 3; List<List<Integer>> pairs = findKSmallestPairs(nums1, nums2, k); System.out.println("最小和的 " + k + " 对元素为:"); for (List<Integer> pair : pairs) { System.out.println(pair.get(0) + ", " + pair.get(1)); } } } ``` 以上展示了如何在 Java 中使用优先队列解决问题[^3]。 --- #### 时间复杂度分析 - 堆操作每次插入/删除的时间复杂度为 \( O(\log m) \),其中 \( m \) 是堆中的节点数量。 - 总体上最多执行 \( O(k \cdot \log (\min(n_1, n_2)))\) 次操作,因此效率较高。 --- #### 结果验证 针对样例输入: ``` array1 = [1, 1, 2, 3] array2 = [1, 2, 3] k = 2 ``` 输出应为: ``` [[1, 1], [1, 1]] 总和为:4 ``` 这表明所选方法能够正确处理此类问题。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值