左神单调栈【C++实现】——进阶版

附:基础 https://blog.csdn.net/shiyideliutang/article/details/103528550

单调栈之山峰形成数对问题

题目分析

再次总结算法思路【某一元素结算的方式】

程序代码完全按照该框架写出来的,理解比较容易

程序源代码C++实现

#include<iostream>
using namespace std;
#include <vector>//矢量vector头文件
#include <stack>//栈的头文件

/**< 打印容器vector中的值 */
void print(vector<int> vec)
{
    //第一种打印方式:迭代器
    for(auto it = vec.begin(); it != vec.end(); it++)
    {
        cout << *it << " ";
    }
    cout << "\n---------------------------\n";
    //第二种打印方式:元素访问
    for(int i = 0; i < vec.size(); i++)
    {
        cout << vec.at(i) << " ";//at函数访问元素
        cout << vec[i] << " ";//[]方式访问元素
    }
    cout << "\n---------------------------\n";
}
/**< 当前容器索引位置的下一个位置 */
//因为是环形结构,所以需要做特殊的处理
int Get_NextIndex(vector<int> vec, int index)
{
    return (index+1)==vec.size()? 0:index+1;
}
/**< 栈中存储的数据结构 */
class ValueTime
{
public:
    int value;
    int times;

public:
    //times初始化采用的是 初始化列表初始化数据成员
    ValueTime(int value):times(1)
    {
        this->value = value;
    }
};
/**< 计算C(2,timses)的数值 */
int GetResult(int times)
{
    return (times==1? 0:(times*(times-1)/2));
}
/** \brief 求解容器中元素组成有效数对的个数
 * \param vec:给定的容器,已经存储已经数据元素
 * \return 最终有效数对的个数
 */
int Communication(vector<int> vec)
{
    //元素数量较少,无法组成数对
    if(vec.size() <= 1)
        return 0;

    int res = 0;//存储最终需要返回数对的个数
//1、寻找容器中第一个Max出现的位置[即容器遍历的起始位置]
    int index_max = 0;
    for(int i = 0; i < vec.size(); i++)
    {
        index_max = vec.at(index_max)<vec.at(i)? i:index_max;
    }
    //创建一个存储ValueTime类的栈,并将index_max作为底压入栈中
    stack<ValueTime> s;
    ValueTime* temp = new ValueTime(vec.at(index_max));
    s.push(*temp);
    delete[] temp;
//2、对整个容器进行遍历
    //采用while循环为了方便是从index_max下一个位置开始到再次到达index_max位置结束
    int index_cur = Get_NextIndex(vec, index_max);
    while(index_cur != index_max)
    {
        // 1)不符合入栈条件[当前元素小于等于栈顶元素],需要将栈顶元素弹出并进行结算
        while(!s.empty() && vec.at(index_cur)>s.top().value)
        {
            int times_cur = s.top().times;
            s.pop();

            res += GetResult(times_cur) + times_cur*2;//求解 C(2,times)+times*2
        }

        // 2)符合入栈要求
          //当前元素等于栈顶元素:直接更新栈顶元素的times
        if(!s.empty() && vec.at(index_cur)==s.top().value)
            s.top().times++;
          //当前元素小于栈顶元素:创建新的ValueTime结构,并压入栈中
        else
        {
            ValueTime* temp2 = new ValueTime(vec.at(index_cur));
            s.push(*temp2);
            delete[] temp2;
        }

        //更新容器迭代器,为下次遍历做准备
        index_cur = Get_NextIndex(vec, index_cur);
    }

//3、整个容器已经遍历完毕,但是栈中仍存在数据
    while(!s.empty())
    {
        if(s.size() > 2)
        {
            int times_cur = s.top().times;
            s.pop();

            res += GetResult(times_cur) + times_cur*2;//求解 C(2,times)+times*2
        }
        else if(s.size() == 2)
        {
            int times_cur = s.top().times;
            s.pop();

            res += GetResult(times_cur) + times_cur;//求解 C(2,times)+times
            if(s.top().times > 1)//倒数第二个数据结算受最后一个元素的times的影响
                res += times_cur;
        }
        else//结算最后一个元素
        {
            res += GetResult(s.top().times);
            s.pop();
        }
    }

    return res;
}

int main()
{
    vector<int> vec;

    cout << "Please input some numbers: ";
    while(cin.peek() != '\n')
    {
        int temp;
        cin >> temp;
        vec.push_back(temp);
    }
    //print(vec);//打印vec容器中存储的元素
    cout << Communication(vec);

    return 0;
}

代码错误分析

针对以下代码
	/**< 当前容器索引位置的下一个位置 */
	//因为是环形结构,所以需要做特殊的处理
	int Get_NextIndex(vector<int> vec, int index)
	{
	    return (index+1)==vec.size()? 0:index+1;
	}
最开始是想利用迭代器来调整环形结构【代码如下所示】,经过调试发现迭代器中的end()并不是自己理解的那样,猜测仅仅作为容器的边界, 不可以简简单单通过((it + 1) == vec.end() ?判断[可以通过调试的方法来进行测试验证]
	/**< 当前容器索引位置的下一个位置 */
	//因为是环形结构,所以需要做特殊的处理
	vector<int>::iterator Get_NextIndex(vector<int> vec, vector<int>::iterator it)
	{
		return ((it + 1) == vec.end() ? vec.begin() : it + 1);
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值