【C++】【手撕】【top K】两个有序数组间相加和的Topk问题;优先队列、最大堆。

本文讲解了一种通过优先队列实现最大路径和问题的解法,涉及最大堆的数据结构应用、坐标标记与去重技巧,以及两种不同的实现方式。重点在于理解优先队列原理,TOPK问题求解,以及数据结构的灵活运用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

在这里插入图片描述

https://www.nowcoder.com/practice/7201cacf73e7495aa5f88b223bbbf6d1?tab=note


一、思路

用最大堆来实现。然后再加上用个bfs来扫描周围的最大值。

即:

  1. 将右下角唯一知道的最大值压入最大堆;
  2. 弹出最大堆中最大的值,这个值就可以加入最终结果中;
  3. 将这个最大值的左边节点和上边节点加入最大堆中。
  4. 继续步骤2.的操作。直到压入了k个答案。

二、难点:

1、标记地址

堆中数据弹出,虽然知道是最大的,但是并不知道其所在坐标。

需要自己定一个数据结构。其中包含了val,和其坐标x、y;

然后定义最大堆的时候,用这个数据结构的val来作为构建堆时比较的值。

我使用了stl中的优先队列,定义的时候,可以声明其比较函数。

2、去重

单纯的这样bfs 可能会进到重复的坐标中。使得一个坐标的值进入两次。

用集合 set来标记对应坐标,防止一个坐标重复进堆。

三、代码

struct nodde {
	int val;
	int x;
	int y;
};
class mycomparison
{
public:
	bool operator() (const nodde& lhs, const nodde&rhs) const
	{
		return (lhs.val < rhs.val);
	}
};
vector<int> topK(vector<int> &arr1, vector<int>&arr2, int k)
{
	int cur1 = arr1.size() - 1, cur2 = arr2.size() - 1;
	priority_queue<nodde, std::vector<nodde>, mycomparison >
		my_heap;
	vector<int> result;
	nodde temp, temp1, temp2;
	temp.val = arr1[cur1] + arr2[cur2];
    unordered_set<string> my_set;
	temp.x = cur1;
	temp.y = cur2;
	my_heap.push(temp);
    my_set.insert(to_string(cur1)+","+to_string(cur2));
	int cnt = 0;
	while (cnt < k)
	{
		temp = my_heap.top();
		my_heap.pop();
		temp1.x = temp.x - 1;
		temp1.y = temp.y;
		// if(temp.x>=0&&temp1.y>=0)
		temp1.val = arr1[temp1.x] + arr2[temp1.y];
		temp2.x = temp.x;
		temp2.y = temp.y - 1;
		temp2.val = arr1[temp2.x] + arr2[temp2.y];

		result.push_back(temp.val);

        if(my_set.count(to_string(temp1.x)+","+to_string(temp1.y)) ==0)
        {
            my_heap.push(temp1);
            my_set.insert(to_string(temp1.x)+","+to_string(temp1.y));
        }
		    
        if(my_set.count(to_string(temp2.x)+","+to_string(temp2.y)) ==0)
        {
            my_heap.push(temp2);
            my_set.insert(to_string(temp2.x)+","+to_string(temp2.y));
        }
		    
		cnt++;


	}

	return result;
}

四、实现:

int main()
{
  int N,K;
    cin>>N>>K;
    vector<int> arr1(N);
    vector<int> arr2(N);
    vector<int> res;

    for(int i=0;i<N;i++){
        cin>>arr1[i];
    }

    for(int i=0;i<N;i++){
        cin>>arr2[i];
    }

    res = topK(arr1,arr2,K);
    for(int i=0;i<res.size();i++){
        cout<<res[i]<<" ";
    }
    cout<<endl;
    return 0;
}

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

在这里插入图片描述

五、更进一步

更进一步可以自己手撕一个最大堆。有时间可以试一试

相对来说有些费时间。

六、其他做法

看到了别人的做法,觉得很棒。思路讲出来作为这种做法的另一种实现吧。

3、思路

也是用优先队列实现,但是不用自己写一个比较函数。

直接构建数据结构的时候重载了比较函数。于是最大堆在比较的时候,直接按照sum比较。

思路一样,只是实现手段不同。记录一下。

class Node {
public:
	int lindex;
	int rindex;
	int sum;
public:
	Node(int l, int r, int s) {
		lindex = l;
		rindex = r;
		sum = s;
	}
	//必须重载
	friend bool operator< (Node l, Node r) {
		return l.sum < r.sum;//从小到大排序
	}

};

参考自:https://www.nowcoder.com/profile/417326246

考察的点:

  1. 优先队列的理解。
  2. TOP K 问题的理解。
  3. 数据结构的熟悉
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值