笔试|面试真题

这篇博客主要介绍了多种编程面试中的常见问题,包括字符串模式匹配、子串移除、排名组合、线程同步、扔鸡蛋问题等。解题思路涉及动态规划、字符串处理、排序和队列等算法,通过实例代码展示了如何解决这些问题。
摘要由CSDN通过智能技术生成

字符串模式匹配

问题描述:

有一个字符串它的构成是词+空格的组合,如“北京 杭州 杭州 北京”, 要求输入一个匹配模式(简单的以字符来写), 比如 a a b b aabb aabb, 来判断该字符串是否符合该模式。

举例:


1. pattern = "abba", str="北京 杭州 杭州 北京" 返回 true

2. pattern = "aabb", str="北京 杭州 杭州 北京" 返回 false

3. pattern = "baab", str="北京 杭州 杭州 北京" 返回 true

解题思路:

  • 对于 p a t t e r n pattern pattern,我们需要将其每一个字符都需要对应 s t r str str 中的一个词。

  • 从左到右同时遍历字符数组和单词数组,并在该过程中:

  • p a t t e r n pattern pattern 字符数组第一次出现某一字符时,根据其在单词数组中的位置,记录该字符对应的单词;

  • p a t t e r n pattern pattern 字符数组第 N N N 次( N > 1 N > 1 N>1 )出现某一字符时,取出该字符应该对应的单词,并与当前字符对应在单词数组中的单词对比,如果相同则继续校验,否则返回 f a l s e false false

  • 如果校验至最后一个单词仍然成立,则返回 t r u e true true

问题:如何知道字符是不是第一次出现呢? 如何记录某一字符所对应的单词呢?

  • 通过 u n o r d e r e d _ m a p unordered\_map unordered_map将字符和单词进行映射
  • 通过 f i n d find find函数可判断该字符(键)是否存在
  • 如果不存在则表示是第一次出现,我们需要建立字符和单词之间的映射关系
  • 否则,如果该字符已经存在,则需要和当前遍历到的单词与该字符已经建立映射关系的单词进行比较。
  • 如果两者不相等,返回 f a l s e false false
  • 否则,继续进行下一个单词的遍历
  • 直到当所有的单词比较完成,返回 t r u e true true

代码实现:

字符串分割的函数

vector<string> split(const string &str, const string &pattern)
{
   
	vector<string>  res;
	size_t start = 0, index = str.find_first_of(pattern, 0);
	while (index != str.npos)
	{
   
		if (start != index)
		{
   
			res.push_back(str.substr(start, index - start));
		}
		start = index + 1;
		index = str.find_first_of(pattern, start);
	}
	if (!str.substr(start).empty())
	{
   

		res.push_back(str.substr(start));
	}

	return res;
}

字符串匹配的函数

bool matchPattern(const string &str, const string &pattern)
{
   
	//首先将str进行拆分
	vector<string> words = split(str, " ");
	//判断分割完成之后的单词长度是否等于模式的长度
	if (words.size() != pattern.length())
	{
   
		return false;
	}
	//建立单词和拆分的单词之间的映射关系
	unordered_map<char, string>   map;
	//从左到右同时遍历字符数组和单词数组
	for (int i = 0; i < pattern.length(); ++i)
	{
   
        //如果字符是第一次出现则建立映射关系
		if (map.find(pattern[i]) == map.end())
		{
   
			map.insert(make_pair(pattern[i], words[i]));
		}
		// 否则直接进行比较
		else
		{
   
			if (map[pattern[i]] != words[i])
			{
   
				return false;
			}
		}
	}
	return true;
}

移除子串

问题描述:

给定一个字符串以及多个子串,对于在字符串中出现的子串可以多次移除,求多次移除后能够得到的最短字符串长度。
输入: 第一行为一个字符串,第二行为多个子串,字符串长度大于0
输出: 多次移除后能够得到的最短字符串长度

示例1:

输入:

"ccdaabcdbb"

["ab","cd"]

输出:

2

解释:
ccdaabcdbb -> ccdacdbb -> cabb -> cb (length = 2)

示例 2:

输入:

"abcabd"

["ab","abcd"]

输出:

0

解释:

abcabd -> abcd -> "" (length = 0)

————————
解题思路:

  • 每次取队列首元素作为要处理的主串
  • 在主串中找到每个子串(该子串有可能重复出现在主串中),将剔除子串之后的主串添加进set集合和queue队列中,并更新剔除子串之后主串的长度
  • 当队列为空时,表示所有的情况都处理完毕,返回最小的长度

代码实现:

int moveSubstr(string &s, unordered_set<string> &dict)
	{
   
		int size = s.size();
		if (size == 0)
		{
   
			return 0;
		}

		queue<string> q;//存放待处理的主串
		unordered_set<string> hashSet;//记录每种可能存在的主串的情况

		int minLen = size;//最小的长度
		q.push(s);//首先把原始主串添加进去
		hashSet.insert(s);

		while (!q.empty())
		{
   
			string s = q.front();//每次取队头元素作为待处理的主串
			q.pop();//从队列中删除,表示该主串将要被处理

            //遍历每个子串
			for (auto it = dict.begin(); it != dict.end(); it++)
			{
   
				string str = *it;
               //在主串中找子串,返回子串中第一个字符出现的位置
				int pos = s.find(str);
				while (pos != s.npos)//找到了
				{
   
				   //new_s表示剔除子串之后的主串
					string new_s = s.substr(0, pos) + s.substr(pos + str.size());
					//没有在hashSet中找到,表示该字符串没有被处理过
					if (hashSet.find(new_s) == hashSet.end())
					{
   
						q.push(new_s);//加入待处理队列
						hashSet.insert(new_s);//加入hashSet中,算是一种优化
						minLen = min(minLen, (int)new_s.size());//更新最小长度
		// 因为可能存在同一个子串在主串中多次出现,我们必须处理该子串在主串中不同位置的情况				
					pos = s.find(str, pos + 1);
				}
			}
		}
		return minLen;
	}

n个人排名,允许并列名次,共有多少种排名结果?

解题思路

  • d p [ i ] [ j ] dp[i][j] dp[i][j]:表示 i i i个人,名次个数为 j j j时,有多少种排名方法
  • j = = 1 j==1 j==1,表示 i i i个人,全部都是并列排名
    i > = j i>=j i>=j,表示有并列排名,也有独占一个名次的
  • 如果 i − 1 i-1 i1个人有 j j j个名次,那么如果第 i i i个人和前边的 i − 1 i-1 i1个人
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值