map例子:魔法咒语问题

题目描述:
哈利波特在魔法学校的必修课之一就是学习魔咒。据说魔法世界有100000种不同的魔咒,哈利很难全部记住,但是为了对抗强敌,他必须在危急时刻能够调用任何一个需要的魔咒,所以他需要你的帮助。

    给你一部魔咒词典。当哈利听到一个魔咒时,你的程序必须告诉他那个魔咒的功能;当哈利需要某个功能但不知道该用什么魔咒时,你的程序要替他找到相应的魔咒。如果他要的魔咒不在词典中,就输出“what?”

输入:

    首先列出词典中不超过100000条不同的魔咒词条,每条格式为:

    [魔咒] 对应功能

    其中“魔咒”和“对应功能”分别为长度不超过20和80的字符串,字符串中保证不包含字符“[”和“]”,且“]”和后面的字符串之间有且仅有一个空格。词典最后一行以“@END@”结束,这一行不属于词典中的词条。
    词典之后的一行包含正整数N(<=1000),随后是N个测试用例。每个测试用例占一行,或者给出“[魔咒]”,或者给出“对应功能”。

输出:
每个测试用例的输出占一行,输出魔咒对应的功能,或者功能对应的魔咒。如果魔咒不在词典中,就输出“what?”

使用map来保存魔法字典;

代码如下:

1、从键盘读取魔法字典

/** \题目  :魔法咒语
 *
 * \author: JasonLee
 * \date  :  2017.11.22
 *
 */
#include <iostream>
#include<map>

using namespace std;

map<string,string> insert_data(map<string,string> &magic_map)
{
    cout<<"please input data,end with \"-1\""<<endl;
    string str;//魔咒
    string func;//功能
    while(cin>>str && str != "-1")
    {
        cin>>func;
        magic_map[str]=func;//插入数据
      //另一种写法:  magic_map.insert(pair<string,string>(str,func));
    }
   return magic_map;
}
int main()
{
    map<string,string> magic_map;//保存魔咒-对应功能值

    
<think>嗯,这个问题看起来是要找出数组中出现次数超过一半的那个元素,也就是所谓的多数元素。那我得想想怎么高效地解决这个问题。题目里说数组的长度可能达到10^7,所以不能用简单的O(n²)或者O(n log n)的方法,必须得找一个线性时间且常数空间的算法。 首先,可能的思路有哪些呢?最常见的两种方法是哈希表统计和摩尔投票法。哈希表的话,遍历数组,记录每个元素出现的次数,然后找到最大的那个。但是这样的话,空间复杂度是O(n),当n很大时可能会占用较多内存。而题目里的数组可能很大,达到千万级别,这时候哈希表虽然可行,但可能不是最优的。 那摩尔投票法应该更合适。摩尔投票法的核心思想是,因为要找的元素超过半数,所以可以通过抵消的方式,剩下的那个就是目标。具体来说,维护一个候选元素和一个计数器。遍历数组,如果当前元素等于候选,计数器加一,否则减一。当计数器减到零时,更换候选为当前元素。这样最后剩下的候选可能就是答案。不过这个方法的前提是数组中确实存在多数元素,而题目中已经保证了这一点,所以最后剩下的候选就肯定是正确结果。 那这样的话,摩尔投票法的时间复杂度是O(n),空间复杂度是O(1),完全符合题目的要求。所以应该用这个方法来实现。 那具体怎么实现呢?举个例子,假设数组是[3,2,3]。初始化候选为None,计数器为0。遍历第一个元素3,此时候选是空,所以设置为3,计数器加1。第二个元素是2,不等于候选,计数器减到0。这时候候选被重置,第三个元素3成为新的候选,计数器加1。遍历结束后候选是3,正确。 那代码的大致步骤应该是: 1. 读取输入,第一行是n,第二行是数组。 2. 初始化候选为None,计数器count为0。 3. 遍历数组中的每一个元素: a. 如果count为0,则将当前元素设为候选。 b. 如果当前元素等于候选,count加1,否则减1。 4. 最后返回候选。 这样就得到了答案。需要注意的是,题目中已经保证存在这样的元素,所以不需要再验证候选是否真的超过半数。但实际情况中,可能需要再遍历一次数组确认,不过根据题意这里可以省略。 那现在需要考虑输入输出问题。比如,输入的数组长度可能很大,所以需要高效地读取输入。例如,在Python中,如果输入很大,用split处理可能会有性能问题吗?对于千万级别的数据,可能需要用更高效的方式,但通常Python的处理方式在这种情况下还是可以接受的,只要输入的读取方式正确。 比如,在读取数组的时候,可能需要用input().split()来分割成列表,然后转换为整数。例如,读取第二行作为列表,然后转换成int的列表。那对于n的值可能很大,比如1e7的话,这样的操作在Python中是否可行?应该可以,不过可能需要足够的内存。 总结下来,代码的大体结构应该是: 读取n,虽然可能题目中的n可能不需要实际用到,但可能需要校验输入是否符合条件?不过题目中可能已经给出正确的输入,所以不需要处理异常情况。 然后读取数组,处理成整数列表,然后应用摩尔投票法。 例如: n = int(input()) nums = list(map(int, input().split())) 然后应用摩尔投票法: candidate = None count = 0 for num in nums: if count == 0: candidate = num if num == candidate: count +=1 else: count -=1 print(candidate) 这样应该就能得到正确结果。这个算法的时间复杂度是O(n),空间复杂度是O(1),完全符合题目要求。 那现在测试一下例子,比如输入数组是[3,2,3]。遍历过程: 初始candidate=None,count=0。 第一个元素3:count是0,所以candidate=3,count=1。 第二个元素2:不等于3,count减到0。 第三个元素3:count是0,所以candidate=3,count=1。 循环结束,输出3,正确。 另一个例子,比如数组是[2,2,1,1,1,2,2],正确结果是2。摩尔投票法的过程: 初始count=0,candidate=None。 元素2:count0→candidate=2,count1。 元素2:相同,count2. 元素1:不同,count1. 元素1:不同,count0. 此时count为0,下一个元素1→candidate=1,count1. 元素2→不同,count0. 最后一个元素2→count0→candidate=2,count1. 最终结果是2。正确。 所以算法是正确的。因此,这个解法应该是正确的。</think>要解决这个问题,我们需要在符文数组中找到出现次数超过一半的**危险符文**。由于数组长度可能极大(接近 $10^7$),必须采用高效的算法。摩尔投票法(Boyer-Moore Voting Algorithm)能在 $O(n)$ 时间复杂度和 $O(1)$ 空间复杂度下解决这类问题。 ### 方法思路 1. **摩尔投票法**:通过抵消策略找到可能的候选元素。维护一个候选符文和计数器: - 遍历数组时,若当前符文与候选相同,计数器加1;否则减1。 - 当计数器归零时,更换候选为当前符文。 2. **关键性质**:由于危险符文的出现次数超过一半,最终剩下的候选必然是它(题目已保证存在)。 ### 解决代码 ```python n = int(input()) nums = list(map(int, input().split())) candidate = None count = 0 for num in nums: if count == 0: candidate = num count += 1 if num == candidate else -1 print(candidate) ``` ### 代码解释 1. **输入处理**:读取数组长度 `n` 和符文数组 `nums`。 2. **初始化变量**:`candidate` 存储当前候选符文,`count` 记录候选的相对数量。 3. **遍历数组**: - 若计数器为0,更新候选为当前元素。 - 根据当前元素是否与候选相同,增减计数器。 4. **输出结果**:最终候选即为危险符文。 该算法高效可靠,完美适应大规模数据场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值