程序员进阶之算法练习(三十六)贪心

前言

万物皆贪心。

正文

1.Filling Shapes

题目链接
题目大意:
有基础的三角图案(如下图-左边),需要填充到3xN的大矩形中,要求:
1、不留空隙;
2、没有重叠;

问,有多少种填充的组合方式。

输入:
数字n,表示3*N的大图案宽度;(1≤𝑛≤60)
输出:
多少种填充方式。

Examples
input
4
output
4
input
1
output
0

题目解析:
n为奇数,则会出现填不满的情况(面积和不相等),此时为0;
n为偶数,对于每3*2的6个格子,只有两种组合方式, 那么总共的方案是2^(n/2)的个数。

代码:

    int n;
    cin >> n;
    if (n % 2) {
        cout << 0 << endl;
    }
    else {
        lld ans = 1;
        for (int i = 0; i < n / 2; ++i) {
            ans *= 2;
        }
        cout << ans << endl;
    }

2.Plus from Picture

题目链接
题目大意:
h行w列的字符,由'*'和'.'两种符号组成。
问字符中是否仅存在一个'+'号,加号的组成方式:
1、中心点是一个'*'号;
2、中心点的上下左右四个方向有一个或以上的连续'*'符号;

并且,除了这个'+'号,其他左右的字符都是'.'。

如果满足上面的条件,则输出"YES",否则输出"NO"。

输入:
第一行是h, w; (1≤ℎ, 𝑤≤500)
接下来是h行字符,每行有w个。

输出:
满足上面的条件,则输出"YES",否则输出"NO"。

Examples
input
5 6
......
..*...
.****.
..*...
..*...
output
YES
input
3 5
..*..
****.
.*...
output
NO

题目解析:
先找到中心点,判断中心点是否为星号;
然后从四个方向去遍历,每个方向至少有1个星号,得到每个方向的星号;
总的星号是否等于图中的星号。
思考🤔:
另外一种简单的做法,以5个星号作为基础图案,遍历整个图找到一个最小的+号。
然后延伸去看长度,最后看是否等于所有星号字符数量。

代码地址

3.Beautiful Lyrics

题目链接
题目大意:
一段悦耳的歌词有两行,每行有两个单词,并且要求:
1、第一行的第一个单词中元音数量,和第二行第一个单词相同;
2、第一行的第二个单词中元音数量,和第二行第二个单词相同;
3、第一行的第二个单词中的最后一个元音,和第二行第二个单词相同。

给出n个单词,问最多能拼出多少段悦耳的歌词,每个单词只能用一次。

输入:
第一行n,表示n个单词;(n<=10^5)
接下来n行,每行包括一个单词。
所有单词的字符总数不会超过10^6。

输出:
第一行数字m,表示m段歌词。
接下来是m段歌词,每段两行。

Examples
input
14
wow
this
is
the
first
mcdics
codeforces
round
hooray
i
am
proud
about
that
output
3
about proud
hooray round
wow first
this is
i that
mcdics am

题目解析:
先去除无关因素的影响,把每个单词的元音提取出来,分类成:
1、单词中元音的长度,分别是len=1、2、3.。。
2、相同长度的元音,分别有a/e/i/o/u 五种结尾的类型。

我们用vec[i][j]表示长度为i,结尾是第j个元音的字符串集合。

再来看看题目的要求,拼出最多的歌词,并且每个单词只能用一次。
而歌词的要求,可以表述为:
1、从相同长度字符串中,取出结尾相同的两个单词,作为第1、2行的第二个单词;
2、从相同长度字符串中,取出长度相同的两个单词,作为第1、2行的第一个单词;

从这里,我们可以得到一个贪心的策略:
a.先两个两个的取出所有长度相同并且元音结尾相同的单词,得到x组,这是可能的最大歌词数量;
b.从剩下的所有单词中,两两取出所有长度相同的单词,得到y组,ans=min(x, y)组;
如果x>y,那么剩下(x-y)组单词还可以两两组成歌词,此时还有ans+=(x-y)/2;

思考🤔:
当x>y时,能否取出x组中3个单词,取出1个步骤b剩下的单词,进行配对呢?
答案是可以,但是没有必要。因为步骤b只会剩下0个或者1个某个长度的单词。

代码地址

4. Split a Number

题目链接
题目大意:
有一个字符串str,表示一个数字(没有前导零),现在需要把这个数字分成两个合法的数字,并且希望和尽可能的小。

输入:
第一行,数字n,表示字符串str的长度;(2≤n≤100000)
第二行,字符串str,表示数字;
输出:
最小的和。

Examples
input
7
1234567
output
1801
input
3
101
output
11

题目解析:
先不考虑复杂度,对于每个位置pos,只要str[pos]不是字符0,那么就可以切分成两个字符串[0, pos) 和 [pos, n)两部分。
那么可以枚举每一个位置,计算一遍数字的和,最终得到一个最小的数字和。
枚举复杂度是O(N),分割数字和计算数字和是(N),总的复杂度是O(N^2);
因为n最大可以为10w,那么这个复杂度是不可以接受的。

容易知道,很多位置的分割,是不可能成为最小和的值。比如说字符串1234567,如果分割成12+34567或者1+234567是明显重复的计算。
由贪心的思想可以知道,分割出来的字符串a、b的长度应该尽可能接近。
对于长度为n字符串,分割成长度为n/2和n-n/2 ,或者(n+1)/2和n-(n+1)/2的组合是最好的。

那么是否枚举这个情况即可?

并不是!因为存在一个数字0的情况。比如说数字123000321,中间的位置都是0。
综合上面的考虑,我们可以将n/2向左延伸,直到找到一个不为零的数字,作为分割点;
同样的,将(n+1)/2向右延伸,知道找到一个不为零的数字,作为分割点。

然后从上面的两个可能,选择一个最小的值。

时间复杂度O(N);

代码:

    int n;
    cin >> n;
    string str;
    cin >> str;
    
    /*
      所有的切分都是[0, t-1], [t, n)  不同的是t的位置不同
     要求,str[t]不能为字符0.
     
     t可以是n/2,n/2+1等
     */
    
    int x = (n + 1) / 2, y = n / 2;
    string ansX = str, ansY = str;
    
    while (x < str.length() && str[x] == '0') {
        ++x;
    }
    if (x < str.length()) {
        ansX = getSplitSum(str, x);
    }
    
    while (y >= 0 && str[y] == '0') {
        --y;
    }
    if (y >= 0) {
        ansY = getSplitSum(str, y);
    }
    
    cout << getMinStr(ansX, ansY) << endl;
    

具体方法的实现

总结

题目1:根据题目的特性,可以看出三角形无法填充33的矩形,只能填充32的矩形,那么大问题就可以划分成多个小问题;
题目2:思路比较明显,重点是在于如何找到中心点,我采用的是看每一行每一列的累积星号数量,求交点;别人直接判断一个最小星号,这种做法更加便捷、快速、简练;
题目3:题目的要求看起来很复杂, 通过分析、细化、抽象,提示要素就只有长度、结尾类型两个参数;按照我们归类出来的参数,进行聚合就很容易决策;
题目4:直接的想法很容易想到,比如说从中间分开;但是考虑到前导零的case,用合适的表达方式,会更加容易去计算。

Coding如逆水行舟,不练则废。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容