LeetCode 856 遞歸思路詳解

  1. 題目描述

給定一個平衡括號字符串 S,按下述規則計算該字符串的分數:

  • () 得 1 分。
  • AB 得 A + B 分,其中 A 和 B 是平衡括號字符串。
  • (A) 得 2 * A 分,其中 A 是平衡括號字符串。

示例 1:

輸入: "()"
輸出: 1

示例 2:

輸入: "(())"
輸出: 2

示例 3:

輸入: "()()"
輸出: 2

示例 4:

輸入: "(()(()))"
輸出: 6

提示:

S 是平衡括號字符串,且只含有 ( 和 ) 。

2 <= S.length <= 50

2.思路過程

根據題目,我們明顯知道這個題百分之一萬是要使用遞歸的思想了,但是遞歸的思想需要把握一個很細粒度的問題,就是怎麼判斷每個遞歸的子問題。然後這些子問題一個一個進行迭代(入棧出棧)計算,最後解決問題,這正是遞歸重點,也正是難點。(聽我裝一會兒ACD吧,mua~)

 

首先,我們定義一個子串的概念:

我們從字符串(...)開始往棧裏面壓,當遇到對稱的符號時(即stack.top()是‘(’,下一個字符是‘)’的時候),就pop出這個元素,正好棧爲空的時候,我們稱之爲子串(...)。例如(());();((())());

這樣的話,我們可以將所有的問題都轉化爲子串(...)的組合:

例如:

(())()是兩個子串(...)(...)相加,A+B的情況。

(()(()))也是一個子串(...)。

我們可以發現一個特點:子串的第一個符號’(‘和最後一個符號‘)’永遠是匹配的一對括號。

這樣的話,就可以將整個問題劃分爲以下幾個子問題:

  1. 判斷S有幾個子串(...),讓這些子串的分數相加即可。
  2. 然後子串裏面有可能又是若干個子串的相加情況,例如(()()),我們就讓2*()()

明白了以上的遞歸的小問題之後,我們就可以進行下手寫代碼了,先把自己的代碼運行情況曬一下,性能不是太好,畢竟自己學識短淺,只能寫到這樣的程度了,同時也證明一下自己不是胡編亂造。嘻嘻。

 

3.代碼實戰

兩個方法:

  • scoreOfParentheses(string S)用來判斷一個字符串裏面有幾個子串。讓這些子串的分數相加就可以了。
  • countScore()傳入的參數永遠是子串(...),與前面分析一樣,必須保證子串的第一個左括號和子串最後一個右括號永遠是保持一對的這個特徵。只有這樣的話,return 2*scoreOfParentheses(S1.substr(1,S1.size()-2));這句話纔可正常執行,他目的就是剝去第一個和最後一個括號,將子串裏面的字符串交給scoreOfParentheses()方法來判斷,子串裏面是不是還有子串相加的情況。

這樣兩個方法相互遞歸。相互配合就將整個問題轉化爲:

子串+子串:分數相加

子串嵌套子串:2*子串

然後over!

具體還是要看代碼,歡迎關注,歡迎來撩!

class Solution {
public: 

    //該方法用於處理一個子串,也就是棧可pop爲empty中的情況
    int countScore(string S1)
    {
        if(S1.size()==2)
        {
            return 1;
        }
        else{
            char ch=S1[0];//S1[0]肯定是'('
            if(S1[1]==')')
            {
                //這是()的情況
                return 1+scoreOfParentheses(S1.substr(2,S1.size()-2));
            }
            else{
            /*”((“的情況,由於S1本身傳進來的時候就是一個子串,也就是不含A+B這種情況。所以還要檢查裏面是不是還有各個子串相加的問題.*/
                return 2*scoreOfParentheses(S1.substr(1,S1.size()-2));
            }
        }
        
    }
  

    //遍歷一個字符串,看看有多少個A+B的情況,例如串(())()中(())和()就是兩個子串
    int scoreOfParentheses(string S) //遍歷整個串,看一個串能夠分成多少個子串
    {
        int total_score=0;
        stack<char> sta1;
        int i1=0;//用於記錄子串的開始位置,
        int i2=0;//i2用於記錄子串的結束位置,i2-i1+1就只子串的長度,可以用來截取子串。
        
        while(i2<=S.size()-1)
        {
            sta1.push(S[i2]);//插入的肯定是‘(’
            while(!sta1.empty())//不空
            {
                i2++;
                if(S[i2]=='(')
                {
                    sta1.push(S[i2]);
                }
                else
                {
                    int top=sta1.top();
                    sta1.pop();
                }
            }//空了之後,說明一個子串(i1<->i2)遍歷完畢,記錄指針i,然後將指針數據傳送給countScore()進行計算子串。
            total_score+=countScore(S.substr(i1,i2-i1+1));
            i2++;
            i1=i2;
        }
        return  total_score;
    }
};

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章