373. Find K Pairs with Smallest Sums

本文介绍了一种寻找两个升序数组中组成最小k对和的高效算法。通过使用最小堆(PriorityQueue)来实现,确保了时间和空间复杂度的有效控制。文章详细解释了算法的具体实现步骤,并给出了完整的Java代码实现。

题意:输入两个整形升序数组,整数k,要求分别从2个数组中取出2个数组成对,输出和最小的k个对。

思路:1 参考leetcode discuss;

   2  PriorityQueue实现最小堆,具体步骤如下:

初始化为array1中的前k个元素(注意,如果array1中的长度小于k,则为array1.length)和array2中的首个元素组成的pair;

每次从堆中剔除首个元素p(即目前堆中pair的和最小),然后将p中对应array2的下标后移(注意后移之前判断是否到达array2的边界),把<(int[2])p[0], p[1]=nums2[index+1]>添加到堆中。

时间复杂度为 O(klogk)。因为堆中的元素最多k个。


public class Solution {
	class Pair{
		int[] pair;
		int idx; //numArry2[curIndex]
		long sum;
		public Pair(int idx, int n1, int n2) {
			super();
			this.idx = idx; //note current searched index of array2
			pair = new int[]{n1, n2};
			sum = (long)n1 + n2;
		}
	}
	class ComPair implements Comparator{
		public int compare(Pair o1, Pair o2) {
			return Long.compare(o1.sum, o2.sum); //o1.sum - o2.sum
		}
	}
	public List kSmallestPairs(int[] nums1, int[] nums2, int k){
		List ret = new ArrayList<>();
		if(nums1 == null || nums2 == null || nums1.length == 0 || nums2.length == 0){
			return ret;
		}
		PriorityQueue q = new PriorityQueue<>(k, new ComPair());
		for(int i = 0; i < nums1.length && i < k; i++){
			q.offer(new Pair(0, nums1[i], nums2[0])); //klogk
		}
		for(int i = 0; i < k && !q.isEmpty(); i++){
			Pair p = q.poll(); //remove head of the queue O(logk)
			ret.add(p.pair);
			if(p.idx < nums2.length-1){
				q.offer(new Pair(p.idx+1, p.pair[0], nums2[p.idx+1]));
			}
		}
		return ret;
	}
}

在 C++ 中,`std::map` 是一种关联容器,用于存储键值对(key-value pairs),其中每个键是唯一的。`map.find(key)` 方法用于查找指定的键是否存在,如果存在,则返回一个指向该键值对的迭代器;如果不存在,则返回 `map.end()`。当找到键时,可以通过迭代器访问其对应的值(即 `second`)。 例如,以下代码展示了如何使用 `map.find()` 并访问 `second`: ```cpp #include <iostream> #include <map> using namespace std; int main() { map<string, int> m; int result; auto it = m.find("1"); if (it != m.end()) result = it->second; else result = -1; cout << result << endl; // 输出 -1,因为键 "1" 尚未插入 m["1"] = 111; // 插入键值对 it = m.find("1"); if (it != m.end()) result = it->second; else result = -1; cout << result << endl; // 输出 111,因为键 "1" 已插入 return 0; } ``` 上述代码中,`it->second` 用于获取迭代器所指向键值对中的值部分。在 `map` 中,每个元素都是 `std::pair<const Key, T>` 类型,其中 `first` 是键,`second` 是对应的值。因此,通过 `it->second` 可以访问或修改与键相关联的值[^1]。 ### 注意事项: - 在访问 `it->second` 之前,必须确保迭代器 `it` 不等于 `m.end()`,否则会导致未定义行为。 - `map.find()` 的时间复杂度为 $O(\log n)$,因为 `std::map` 通常以红黑树实现。 - 如果希望在未找到键时提供默认值,可以直接使用 `map[key]`,但如果键不存在,则会自动插入一个默认构造的值(例如 `int()` 返回 0),这可能会影响性能或逻辑。 ### 替代方法 除了 `map.find()`,还可以使用 `map.at()` 方法来访问值。与 `map[key]` 不同,`map.at(key)` 在键不存在时会抛出 `std::out_of_range` 异常,而不是插入默认值: ```cpp try { int value = m.at("1"); cout << value << endl; } catch (const std::out_of_range& e) { cout << "Key not found!" << endl; } ``` 这种方法适用于需要明确处理键不存在的情况。 ### 使用场景 `map.find()->second` 常用于需要高效查找并访问值的场景,尤其是在键值对集合较大的情况下。由于 `map` 提供有序的键存储,因此适用于需要按键排序的场景。如果不需要按键排序且追求更快的查找速度,可以考虑使用 `std::unordered_map`,其查找平均时间复杂度为 $O(1)$。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值