算法训练:贪心与回溯

目录

1.手套(贪心算法)

2.字符串通配符(回溯算法)


1.手套

题目描述:

在地下室里放着n种颜色的手套,手套分左右手,但是每种颜色的左右手手套个数不一定相同。A先生现在要出门,所以他要去地下室选手套。但是昏暗的灯光让 他无法分辨手套的颜色,只能分辨出左右手。所以他会多拿一些手套,然后选出一双颜色相同的左右手手套。现在的问题是,他至少要拿多少只手套(左手加右 手),才能保证一定能选出一双颜色相同的手套。 给定颜色种数n(1≤n≤13),同时给定两个长度为n的数组left,right,分别代表每种颜色左右手手套的数量。数据保证左右的手套总数均不超过26,且一定存在至少一 种合法方案。

  

输入描述:第一行输入一个正整数n(n ≤ 1000) 第二行为n个数正整数x (x ≤ 1000)

 

输出描述:输出可以产生的幸运的袋子数 

 

测试样例:

 

4,[0,7,1,6],[1,5,0,6]

 

返回:10(解释:可以左手手套取2只,右手手套取8只)

思路分析:

我们从题目中可以看到,我们需要得出一个结果就是至少要拿多少只手套。这里一般采用贪心算法。我们来分析一下:

因为在拿手套的时候,是盲拿的,拿了多少不知道,拿的是右手还是左手的也不知道。因此,我们就必须保证,在拿手套的时候,拿到的数量最起码能够覆盖左手或者右手的所有颜色!基于此再拿一只另外一只手的手套,便是我们需要的结果。

比如测试样例中,我们需要拿到覆盖左手的手套颜色那么多的数量,那就将左手手套的数量全部加起来,然后减去最少的那个颜色的数量再加一,这就是覆盖了左手的颜色可拿到至少的左手手套的数量了!然后再从右手的手套随便取一个,那么就能够保证至少有一个颜色的手套可以匹配得上。

但是要注意0数量的情况,对于0数量的颜色的手套,我们需要将其额外拿出来,因为如果一种颜色的手套,它的右手或者左手的手套数量为0,即使覆盖了一只手的手套颜色的数量,也可能会使另外一只手的手套匹配不上的问题。

代码如下:

class Gloves
{
public:
	int FindMininum(int n, vector<int> left, vector<int>right)
	{
		int left_sum = 0, left_min = INT_MAX;
		int right_sum = 0, right_min = INT_MAX;

		int sum = 0;//用于统计另一只手的手套为零时,另一只手的手套的个数
		for (int i = 0; i < n; ++i)
		{
			if (left[i] * right[i] == 0)
			{
				sum += left[i] + right[i];//需要额外统计
			}
			else
			{
				left_sum += left[i];
				left_min = left_min < left[i] ? left_min : left[i];
				right_sum += right[i];
				right_min = right_min < right[i] ? right_min : right[i];
			}
		}

		//将它们加起来,sum + min(left_sum - left_min + 1, right_sum - right_min + 1)这一步
		//相当于把一只手的所有颜色的手套都拿了,然后再加个1,就是从另外一只手的手套堆取一只。
		//这样就必定能够至少匹配一双出来。
		return sum + min(left_sum - left_min + 1, right_sum - right_min + 1) + 1;
	}
};

2.字符串通配符

题目描述:

问题描述:在计算机中,通配符一种特殊语法,广泛应用于文件搜索、数据库、正则表达式等领域。现要求各位实现字符串通配符的算法。 要求: 实现如下2个通配符: *:匹配0个或以上的字符(注:能被*和?匹配的字符仅由英文字母和数字0到9组成,下同) ?:匹配1个字符 注意:匹配时不区分大小写。 输入: 通配符表达式; 一组字符串。 输出: 返回不区分大小写的匹配结果,匹配成功输出true,匹配失败输出false

 

输入描述:先输入一个带有通配符的字符串,再输入一个需要匹配的字符串

 

输出描述:返回不区分大小写的匹配结果,匹配成功输出true,匹配失败输出false

 

样例:

输入: te?*.*

输出: txtec.cpp

返回:false

 

输入: te?*.*

输出: tetedsdsdc.cpp

返回:true

思路分析

要匹配字符串,有以下三种情况:

①它是字符,并且相等。那么就直接往下走。

②它是'?',问号可以跟任何字符匹配。那么直接往下走。

③它是'*',星号有三种情况:

⭐它没得匹配,即已经走完,这个星号不需要匹配任何字符。

⭐它只需要匹配一个字符,那么直接往下走。

⭐它需要匹配很多个字符,那么这个字符串不需要往下走,需要匹配的字符串往下走。

往下走即使用回溯,即递归算法。

#include <iostream>
#include <string>
using namespace std;
bool strMach(const char* parten, const char* str)
{
    if (*parten == '\0' && *str == '\0')
    {
        return true;
    }
    if (*parten == '\0' || *str == '\0')
    {
        return false;
    }

    if (*parten == '?')
    {
        return strMach(parten + 1, str + 1);
    }
    else if (*parten == '*')
    {
        return strMach(parten + 1, str) || strMach(parten + 1, str + 1) || strMach(parten, str + 1);
    }
    else if (*parten == *str)
    {
        return strMach(parten + 1, str + 1);
    }
    return false;
}
int main() {

    string parten, str;
    cin >> parten >> str;
    bool ret = strMach(parten.c_str(), str.c_str());
    if (ret)
    {
        cout << "true" << endl;
    }
    else {
        cout << "false" << endl;
    }
    return 0;
}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山雾隐藏的黄昏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值