【模拟算法系列】详解5道题

本文讲解模拟算法系列的5道经典题,在讲解题目的同时提供AC代码,点击题目即可打开对应OJ链接

目录

模拟算法的介绍

1、替换所有的问号

2、提莫攻击

3、 Z 字形变换

4、外观数列

5、数青蛙


模拟算法的介绍

题目中明确告诉你要干什么,思路简单,较考察代码能力

做题步骤:

  • 模拟算法流程(自己一定要演示一下) 
  • 把流程转换为代码

大部分的模拟题的优化方式都是通过找规律


1、替换所有的问号

 算法思路:

从前往后遍历整个字符串,当出现问号时,枚举a~z字符替换,只要不跟前面或后面的字符相等即可,边界问题:若?为第一个字符,只判断后面即可,若?为最后一个字符,只判断前面即可

class Solution {
public:
    string modifyString(string s) {
        int n = s.size();
        for (int i = 0; i < n; i++)
        {
            if (s[i] == '?'){
                for (char ch = 'a'; ch <= 'z'; ch++)
                {   //如果为第一个位置或最后一个位置,则利用||不用判断前面或后面的字符
                    if ((i == 0 || ch != s[i - 1]) && (i == n - 1 || ch != s[i + 1]))
                    {
                        s[i] = ch;
                        break;
                    }
                }
            }
        }
        return s;
    }
};

2、提莫攻击

 算法思路:

模拟+分情况讨论。
计算相邻两个时间点的差值:

  • 如果差值大于等于中毒时间,说明上次中毒可以持续 duration 秒;
  • 如果差值小于中毒时间,那么上次的中毒只能持续两者的差值
class Solution {
public:
    int findPoisonedDuration(vector<int>& timeSeries, int duration) {
        int ret = 0;
        for (int i = 1; i < timeSeries.size(); i++)
        {
            int x = timeSeries[i] - timeSeries[i - 1];
            if (x >= duration) ret += duration;
            else ret += x;
        }
        return ret + duration;//要把最后一个位置的中毒时间加上
    }
};

3、 Z 字形变换

 分析题目:

解题思路:

 可以定义一个字符串用来保存结果,当遇到目标字符就利用string的+=来保存结果,所以我们只需知道需要保存的字符的顺序和位置即可

下面找规律按照①~④推得来:

class Solution {
public:
    string convert(string s, int numRows) {
        //处理边界情况【处理第一行时会死循环,报超出时间限制】
        if (numRows == 1) return s;

        string ret;//保存结果的字符串

        //1、处理第一行
        int d = 2 * numRows - 2, n = s.size();
        for (int i = 0; i < n; i += d) ret += s[i];

        //2、处理中间行
        for (int k = 1; k < numRows - 1; k++)//循环中间的每一行
        {
            for (int i = k, j = d - k; i < n || j < n; i += d, j += d)
            {   //两个元素哪个没走到头就加哪个
                if (i < n) ret += s[i];
                if (j < n) ret += s[j];
            }
        }

        //3、处理最后一行
        for (int i = numRows - 1; i < n; i += d) ret += s[i];

        return ret;
    }
};

4、外观数列

 解题思路:

class Solution {
public:
    string countAndSay(int n) {
        string ret = "1";//初始状态
        
        for (int i = 1; i < n; i++) //进行n-1次即为答案
        {
            string tmp;//要用临时变量保存每次得到的结果,直接加到ret上就累积了,结果不对
            int len = ret.size();
            for (int left = 0, right = 0; right < len;)
            {
                while (right < len && ret[left] == ret[right]) right++;//找连续相同区域
                tmp += to_string(right - left) + ret[left];//利用to_string将整数转换为字符串
                left = right;
            }
            ret = tmp;//每次都更新下结果
        }
        return ret;
    }
};

5、数青蛙

解题思路:模拟+哈希表

 注:最后模拟完后,哈希表中应该只有k位置有数,其他位置都应没数,如果有,则不符题意,即代码最后还要做一下判断

class Solution {
public:
    int minNumberOfFrogs(string croakOfFrogs) {
        string t = "croak";
        int n = t.size();
        vector<int> hash(n); //数组模拟哈希表

        unordered_map<char, int> index; //保存字符及其下标,方便找到字符
        for (int i = 0; i < n; i++) index[t[i]] = i;

        for (auto ch : croakOfFrogs)
        {
            if (ch == 'c')
            {
                if (hash[n - 1] != 0) hash[n - 1]--;
                hash[0]++;
            }
            else
            {
                int i = index[ch];//先获取该字符的下标
                if (hash[i - 1] == 0) return -1;//若前驱字符不存在
                hash[i - 1]--, hash[i]++;
            }
        }

        //判断除了k位置外,其他的位置若也有数,则说明不是croak的有效组合
        for (int i = 0; i < n - 1; i++) 
            if (hash[i] != 0) return -1;
        return hash[n - 1];//k位置出现几次,就至少几只青蛙
    }
};

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
巡回置换问题是指在一个完全图中,每个顶点之间都有一条边,求一条经过每个顶点一次且仅一次的回路,使得回路的总长度最小。这个问题是一个NP难问题,因此通常使用启发式算法来解决。其中一种启发式算法是遗传算法。 遗传算法是一种模拟自然进化过程的优化算法。在巡回置换问题中,可以将每个可能的回路看作一个个体,通过交叉、变异等操作来产生新的个体,并通过适应度函数来评估每个个体的优劣程度。经过多代进化,最终得到一个较优的回路。 以下是巡回置换问题的遗传算法的Python实现: ```python import random # 生成初始种群 def generate_population(city_num, pop_size): population = [] for i in range(pop_size): chromosome = list(range(city_num)) random.shuffle(chromosome) population.append(chromosome) return population # 计算路径长度 def get_distance(city1, city2): return ((city1[0] - city2[0]) ** 2 + (city1[1] - city2[1]) ** 2) ** 0.5 def get_path_length(path, cities): length = 0 for i in range(len(path) - 1): length += get_distance(cities[path[i]], cities[path[i+1]]) length += get_distance(cities[path[-1]], cities[path[0]]) return length # 选择操作 def selection(population, cities): fitness_list = [1 / get_path_length(chromosome, cities) for chromosome in population] total_fitness = sum(fitness_list) probability_list = [fitness / total_fitness for fitness in fitness_list] selected_population = [] for i in range(len(population)): selected_population.append(random.choices(population, probability_list)[0]) return selected_population # 交叉操作 def crossover(parent1, parent2): child = [-1] * len(parent1) start = random.randint(0, len(parent1) - 1) end = random.randint(0, len(parent1) - 1) if start > end: start, end = end, start for i in range(start, end+1): child[i] = parent1[i] j = 0 for i in range(len(parent2)): if child[j] == -1: if parent2[i] not in child: child[j] = parent2[i] j += 1 else: j += 1 return child # 变异操作 def mutation(chromosome): index1 = random.randint(0, len(chromosome) - 1) index2 = random.randint(0, len(chromosome) - 1) chromosome[index1], chromosome[index2] = chromosome[index2], chromosome[index1] return chromosome # 遗传算法主函数 def genetic_algorithm(city_list, pop_size, generation_num, crossover_rate, mutation_rate): population = generate_population(len(city_list), pop_size) for i in range(generation_num): population = selection(population, city_list) new_population = [] for j in range(pop_size): parent1 = random.choice(population) if random.random() < crossover_rate: parent2 = random.choice(population) child = crossover(parent1, parent2) else: child = parent1 if random.random() < mutation_rate: child = mutation(child) new_population.append(child) population = new_population best_path = min(population, key=lambda x: get_path_length(x, city_list)) best_length = get_path_length(best_path, city_list) return best_path, best_length # 测试 if __name__ == '__main__': city_list = [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)] best_path, best_length = genetic_algorithm(city_list, 100, 1000, 0.8, 0.1) print('最优路径:', best_path) print('最短路径长度:', best_length) ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值