当前位置: 首页 > news >正文

6.23 deque | 优先队列_堆排序 | 博弈论

lc1753.移除石子

贪心

为了将分数最大化,每次将最大的两个数进行减少,(循环中sort),直到有两堆为零。

class Solution {
public:
    int maximumScore(int a, int b, int c) {
        int ans = 0;
        vector<int> rec = {a, b, c};
        sort(rec.begin(), rec.end());
        while (rec[1] != 0) { 
            ans++;
            rec[1]--; rec[2]--;
            sort(rec.begin(), rec.end());

        } 
        return ans;
    }
};

将上面循环当中的sort方法,可以采取优先队列来维护。

priority_queue   top  pop  push

class Solution {
public:
    int maximumScore(int a, int b, int c) {
        // 使用最大堆(优先队列)存储石子数量
        priority_queue<int> maxHeap;
        maxHeap.push(a);
        maxHeap.push(b);
        maxHeap.push(c);

        int score = 0;

        while (maxHeap.size() >= 2) {
            // 取出最大的两堆
            int first = maxHeap.top(); maxHeap.pop();
            int second = maxHeap.top(); maxHeap.pop();

            // 各取一个石子
            first--;
            second--;
            score++;

            // 如果还有石子,放回堆中
            if (first > 0) maxHeap.push(first);
            if (second > 0) maxHeap.push(second);
        }

        return score;
    }
};

lc451. 频次排序

桶排序

class Solution {
public:
    string frequencySort(string s) {
        string res;
        unordered_map<char, int> dict;
        for (char c : s) ++dict[c];
        vector<string> sub(s.size() + 1);
        for (auto &[key, value] : dict)
            sub[value].append(value, key);

//桶排序
        for (int i = s.size(); i > 0; --i)
            if (sub[i].size()) res.append(sub[i]);
        return res;
    }
};

堆排序

hash统计好频次后,v,k到priority_queue中,实现排序,然后再top pop取出

class Solution {

public:

    string frequencySort(string s) {

        string res;

        unordered_map<char, int> dict;

        for (char c : s) ++dict[c];

        priority_queue<pair<int, char>> sub;

        for (auto &[key, value] : dict)

            sub.push({value, key});

//实现降序排序

        while (sub.size()) {

            res.append(sub.top().first, sub.top().second);

            sub.pop();

        }

        return res;

    }

};

 

lc292 博弈论

先后手

博弈论就是研究人们在互动决策时,如何根据他人可能的选择来调整自己的策略,以追求利益最大化的学问,就像下棋时你得琢磨对手下一步怎么走,再决定自己怎么落子。

总结:对于范围内判断

%(min+max)==0  那么就一定是对方赢

 

 class Solution {
public:
    bool canWinNim(int n) {
        return n % 4 != 0;
    }
};

典型博弈论,直接return true也行

 class Solution {

public:

    bool stoneGame(vector<int>& piles) 

    {

        sort(piles.rbegin(),piles.rend());

        int ali=0,bob=0;

        for(int i=0;i<piles.size();i++)

        {

            if(i%2==0) ali+=piles[i];

            else bob+=piles[i];

        }

        return ali>bob;

    }

};

常见博弈论

- 必胜态和必败态:

比如和朋友轮流拿糖果,只剩1颗时你拿就赢(必胜态),但如果轮到你时只剩2颗且规则是每人最多拿1颗,你拿完对方就能拿最后1颗(你处于必败态)。

(本题就是%(min+max)后的拓展


- Nim游戏(取石子):

三堆石子分别有3、4、5颗,和朋友轮流拿,每次从一堆里拿任意数量。这时候算3⊕4⊕5=2≠0,说明先手能赢(比如先从5颗里拿2颗,让剩下的异或和为0,之后对方怎么拿你都按规则调整,最后必赢)


- SG函数(玩跳格子):

每个格子有不同规则(比如从格子A能跳到B/C/D),SG函数就像给每个格子算“安全值”,把多个格子的SG值异或起来,不为0时先手能赢,本质是看你能不能跳到“安全格子”让对手陷入被动。


- 公平组合游戏:

类似“石头剪刀布”,两人规则一样,胜负只看双方选择,没有运气成分(但算法题里常是取物品这类有固定规则的博弈)。

博弈论的异或推论操作

 


priority_queue 优先队列 

- 最大堆: priority_queue<T> pq; 

- top最小堆: priority_queue<T, vector<T>, greater<T>> pq;

操作push_back,pop_back,top

 

lc884

优解:

将两个字符串合二为一,统计只出现一次的即可 

最开始顺手写的,实际项目的话,可以解耦出cntWord,和compare函数

class Solution {
public:
    vector<string> uncommonFromSentences(string s1, string s2) {
        unordered_map<string,int> hash1;
        unordered_map<string,int> hash2;
        
        for(int i=0;i<s1.size();i++)
        {
            string tmp;
            while(s1[i]!=' ' && i<s1.size())
            {
                tmp+=s1[i];
                i++;
            }
            hash1[tmp]++;
        }
        
        for(int i=0;i<s2.size();i++)
        {
            string tmp;
            while(s2[i]!=' ' && i<s2.size())
            {
                tmp+=s2[i];
                i++;
            }
            hash2[tmp]++;
        }
        vector<string> ret;
        for(auto& [a,b]:hash1)
        {
            if(b==1 && !hash2.count(a))
            {
                ret.push_back(a);
            }
        }
        for(auto& [a,b]:hash2)
        {
            if(b==1 && !hash1.count(a))
            {
                ret.push_back(a);
            }
        }
        return ret;
    }
};

deque双端队列

c++数据结构可以头插,还可以下标访问元素

同时支持高效头插和下标访问的数据结构较少,但以下两种方案可满足需求(需权衡效率):

 

1.  std::deque (双端队列)

- 头插支持:使用  push_front() ,时间复杂度 O(1)。

- 下标访问:支持  operator[]  和  at() ,时间复杂度 O(1)。

- 原理:内部通过分段动态数组实现,头尾插入无需移动全部元素,但下标访问时可能需要跨段寻址(效率略低于  vector ,但仍为常数时间)。

- 示例:

#include <deque>

std::deque<int> dq;

dq.push_front(10); // 头插

dq.push_front(20); // 现在 dq[0]=20, dq[1]=10

int first = dq[0]; // 下标访问

 

 

2. 自定义结构( list  +  map  组合)

 - 方案:用  std::list  实现头插(O(1)),同时用  std::map<int, list::iterator>  记录下标与迭代器的映射,实现下标访问。

- 复杂度:

- 头插:O(1)( list  原生支持)。

- 下标访问:O(log n)( map  查找)。

- 示例(简化逻辑):

#include <list>

#include <map>

 

template <typename T>

class CustomStructure {

private:

    std::list<T> data;

    std::map<int, typename std::list<T>::iterator> indexMap;

public:

    void push_front(const T& val) {

        data.push_front(val);

        indexMap[0] = data.begin(); // 头插后更新索引0

        // 其他索引需后移,实际需遍历map调整,复杂度O(n),此处简化

    }

    T& operator[](int idx) {

        return *indexMap[idx];

    }

};

 

 

缺点:实现复杂,头插时维护索引映射需 O(n) 时间,仅适用于特定场景。

不推荐方案

-  std::vector :头插需移动所有元素(O(n)),效率极低,仅尾插高效。

-  std::list :不支持下标访问(需从头遍历,O(n))。

 

最优选择建议

- 若下标访问频率高且头插频率低,优先选  std::deque ,其综合性能更优;

- 若头插频率极高且必须下标访问,可考虑自定义结构,但需接受额外的时间和代码复杂度。

lc2899   deque双端队列  push_front

选对数据结构,做题就是很简单(=^・ω・^=)

class Solution {
public:
    vector<int> lastVisitedIntegers(vector<int>& nums) 
    {
        vector<int> ans;
        deque<int> dq;
        int n=nums.size();
        int cnt=0;
        for(int i=0;i<n;i++)
        {
            if(nums[i]>=0)
            {
                dq.push_front(nums[i]);
                cnt=0;
            }
            else
            {
                cnt++;
                if(cnt<=dq.size())
                {
             ans.push_back(dq[cnt-1]);
                }
                else
                   ans.push_back(-1);
            }
        }
        return ans;
    }
};

lc905 奇偶排序

deque

class Solution {
public:
    vector<int> sortArrayByParity(vector<int>& nums) 
    {
        deque<int> dq;
        for(auto& n:nums)
        {
            if(n%2==0)
                dq.push_front(n);
            else
                dq.push_back(n);
        }
        vector<int> ret;
        for(auto& d:dq)
            ret.push_back(d);
       return ret;
    }
};

 

相关文章:

  • Python 数据分析与可视化 Day 5 - 数据可视化入门(Matplotlib Seaborn)
  • 基于springboot+uniapp的“川味游”app的设计与实现7000字论文
  • go channel用法
  • 微算法科技(NASDAQ:MLGO)研发可信共识算法TCA,解决区块链微服务中的数据一致性与安全挑战
  • 拼团系统多层限流架构详解
  • 针对我的简历模拟面试
  • 采集MFC软件的数据方法记录
  • Flutter开发中记录一个非常好用的图片缓存清理的插件
  • HTML语义化标签
  • Unity编辑器扩展:UI绑定复制工具
  • AI绘画工具实测:Stable Diffusion本地部署指
  • 【目标检测】图像处理基础:像素、分辨率与图像格式解析
  • UE5 开发遇到的bug整理
  • EEG分类攻略2-Welch 周期图
  • 开发上门按摩APP应具备哪些安全保障功能?
  • MySQL 事务实现机制详解
  • 半导体行业中的专用标准产品ASSP是什么?
  • 简析自动驾驶产业链及其核心技术体系
  • 前端跨域解决方案(7):Node中间件
  • 人机融合智能 | 人智交互的神经人因学方法
  • 简阳建设网站公司/十大室内设计网站
  • 四川做网站的公司/爱站网关键词长尾挖掘
  • 彩票做网站犯法吗/网络策划是做什么的
  • 无锡做网站f7wl/成都企业seo
  • 网站建设费用 优帮云/百度排行榜
  • 沈阳网站建设优化/自动点击竞价广告软件