Xiaojieの学習プロセスNo.1111。効果的なブラケットのモザイクの深さ

質問は
、アルゴリズムの初心者としてLeetCode 自身から転送され、LeetCodeの質問についての考えを記録します。そのアイデアは主に公式のソリューションとネチズンの方法に言及しています。

トピックの説明

有効なブラケット文字列の定義:左ブラケットごとに、対応する右ブラケットが見つかります。逆も同様です。詳細については、質問の最後にある「有効なブラケット文字列」セクションを参照してください。

入れ子の深さの定義:入れ子になっている有効なかっこ文字列の数、深さ(A)は、有効なかっこ文字列Aの入れ子の深さを示します。詳細については、質問の最後にある「ネストの深さ」セクションを参照してください。

次の図に、有効なブラケット文字列タイプと対応するネストの深さの計算方法を示します。

ここに画像の説明を挿入

「有効なブラケット文字列」シーケンスを与え、それを2つのばらばらの有効なブラケット文字列AとBに分割し、これら2つの文字列の深さを最小化してください。

不相交:每个 seq[i] 只能分给 A 和 B 二者中的一个,不能既属于 A 也属于 B 。
A 或 B 中的元素在原字符串中可以不连续。
A.length + B.length = seq.length
深度最小:max(depth(A), depth(B)) 的可能取值最小。 

分割スキームは、長さseq.lengthの回答配列answerで表され、コーディングルールは次のとおりです。

answer[i] = 0,seq[i] 分给 A 。
answer[i] = 1,seq[i] 分给 B 。

要件を満たす回答が複数ある場合は、いずれか1つを返してください。

例1:

入力:seq = "(()())"
出力:[0,1,1,1,1,0]

例2:

入力:seq = "()(())()"
出力:[0,0,0,1,1,0,1,1]
説明:この例に対する答えは一意ではありません。
ここをクリックして、A = "()()"、B = "()()"、max(深さ(A)、深さ(B))= 1を出力します。これらの深さは最小です。
[1,1,1,0,0,1,1,1]のように、これも正しい結果です。ここで、A = "()()()"、B = "()"、max(深さ(A)、深さ) (B))= 1。

ヒント:

1 < seq.size <= 10000

有効なブラケット文字列:

"("と ")"のみで構成される文字列の場合、左角括弧ごとに対応する右角括弧が見つかります。逆も同様です。
次のケースも有効な括弧文字列です。

  1. 空の文字列
  2. 接続、ABと書くことができます(AとBが接続されています)。AとBは両方とも有効な括弧文字列です。
  3. ネストされ、(A)として記述できます。Aは有効なブラケット文字列です

ネストの深さ:

同様に、有効なブラケット文字列sの入れ子の深さ(S)を定義できます。

  1. sが空の場合、深さ( "")= 0
  2. sはAとBの間の接続であり、深さ(A + B)= max(深さ(A)、深さ(B))であり、AとBはどちらも有効な括弧文字列です。
  3. sは入れ子の状況、深さ( "(" + A + ")")= 1 +深さ(A)、Aは有効なブラケット文字列

たとえば、 ""、 "()()"、および "()(()())"はすべて有効な括弧文字列であり、ネストの深さはそれぞれ0、1、2ですが、 ")("および "(( )”有効な括弧文字列ではありません。

ソース:LeetCode
リンク:https ://leetcode-cn.com/problems/maximum-nesting-depth-of-two-valid-parentheses-strings

解決策

1.スタック

seq = "(()())"
ans = []
d = 0
for c in seq:
    if c == '(':
        d += 1
        ans.append(d % 2)
    if c == ')':
        ans.append(d % 2)
        d -= 1
print(ans)

出力結果:

[1, 0, 0, 0, 0, 1]

このソリューションは公式のソリューションを参照しており
、変数を使用して記録スタックのサイズをシミュレートし、変数dを使用してスタックの深さを記録しています。文字列をトラバースします。現在の文字が「(」の場合はスタックにプッシュされます。現在の文字が「)」の場合は「(」がポップされます。変数dは「(」の数を記録します。このとき、パリティの深さを使用します。性別、平均して2つのグループに分けます(例:d%2)。

2.異なるグループ内の2つの連続した(または)グループ

seq = "(()())"
ans = [1]
for i in range(1, len(seq)):
    ans.append(1 - ans[i - 1]) if seq[i] == seq[i - 1] else ans.append(ans[i - 1])
print(ans)

出力結果:

[1, 0, 0, 0, 0, 1]

方法1を考えると、2つの連続した(または)グループが同じグループに分割されない限り、この方法が得られます。
最初に、最初の "("を奇数配列(つまり、ans = [1])に分割し、次にループを使用して、2番目が最初のものと同じであるかどうかを判断します。同じ場合は、別のグループ(つまり、 :追加(1-ans [i-1]))、それが異なる場合は、以前と同じグループに入れます(つまり:(ans [i-1])を追加します)。

3.簡略化されたソリューション1

seq = "(()())"
ans = []
for i, c in enumerate(seq):
    ans.append((i & 1) ^ (c == '('))
print(ans)

出力結果:

[1, 0, 0, 0, 0, 1]

メソッド1の簡略化
(i&1)^(c == '(')、記号「^」は両側で1を返しません。それ以外の場合は0を返します。
これは有効な括弧であるため、それらの数のパリティは異なる必要があります。 1は異なる必要があります。cは '('であり、c == '('も異なる必要があるため、結局、(i&1)^(c == '(')の値は0または1と同じでなければなりません。 、同じグループに分けられる目的を達成するため。

オリジナルの記事を10件公開 Likes0 Visits50

おすすめ

転載: blog.csdn.net/z55947810/article/details/105584995