华为OD 消消乐游戏

发布于:2025-07-15 ⋅ 阅读:(17) ⋅ 点赞:(0)

1. 题意

游戏规则:输入一个只包含英文字母的字符串,字符串中的两个字母如果相邻且相同,就可以消除。
在字符串上反复执行消除的动作,直到无法继续消除为止,此时游戏结束。
输出最终得到的字符串长度。

输入
输入原始字符串 str,需满足:
只能包含大小写英文字母(大小写敏感);
长度不超过 100。
输出
输出游戏结束后,最终剩余字符串的长度。
备注
若输入中包含非大小写英文字母(如数字、符号等),视为异常输入,直接返回 0。

样例一
input:
gg
output:
0
样例二
input:
adbbdc
output:
2

2. 题解

这个题目应该是比较典型的栈的应用,但是我写的时候没有想到,只想到了双指针的写法,还有bug,没有处理从头开始消去的情况。

2.1 为什么只需要从左往右考虑?

因为消去操作满足交换和结律,因此顺序并不重要,最后得到的字符串一定是一样的。

" a a a a " ↔ " ( a a ) a a " ↔ " a a ( a a ) " ↔ " a ( a a ) a " ↔ " a a " ⇒ " " "aaaa"\leftrightarrow"(aa)aa" \leftrightarrow"aa(aa)"\leftrightarrow"a(aa)a" \leftrightarrow"aa" \Rightarrow"" "aaaa""(aa)aa""aa(aa)""a(aa)a""aa"""

2.2 栈的解法

从左往右逐个处理字符串中的元素,如果当前元素和栈顶元素一样,说明需要执行消去操作,否则就将当前元素入栈。重复操作直到字符串处理完毕,栈中剩余的字符串就是消去后的字符串。

void solve2()
{
    stack<char> st;

    for (auto c: s) {
        if (!st.empty() && st.top() == c ) {
            st.pop();
        }
        else {
            st.push(c);
        }
    }
    
    ans = st.size();
}

2.3 双指针解法

我们可以通过双指针分别往左右扩展来得到需要消去的区间。

初始化时, r = l + 1 r=l+1 r=l+1,最终我们消去的区间的为 [ l + 1 , r − 1 ] [l+1,r-1] [l+1,r1],因此需要减去的长度为 r − l − 1 r-l-1 rl1

但有一种情况,我们无法处理,那就是之前提到的从后面可以扩展到前面已经消除的区间,比如样例 " a a b b c c " "aabbcc" "aabbcc"

所以我们需要去重,为此我们在每次获得了消除完区间后,用一个变量pre_right保存消除区间的右边界。

下一次消除的区间左边界最多扩展到pre_right,就停止扩展以避免重复。


void solve1()
{
    int l = 0;
    int r = l + 1;
    int n = s.size();
    
    ans = n;

    int pre_right = -1;
    while ( r < n) {
        r = l + 1;
        while ( l > pre_right && r < n && (s[l] == s[r])) {
            l--;
            r++;
        }
        //cout << l << " " << r << endl; 
        ans -= ( r - l - 1);

        if ( r - l > 1) {
            pre_right = r - 1;
        }
        
        l = r;
    }

    
}

3. 参考

KJ.JK


网站公告

今日签到

点亮在社区的每一天
去签到