學渣帶你刷Leetcode0087擾亂字符串

題目描述

給定一個字符串 s1,我們可以把它遞歸地分割成兩個非空子字符串,從而將其表示爲二叉樹。

下圖是字符串 s1 = "great" 的一種可能的表示形式。

    great
   /    \
  gr    eat
 / \    /  \
g   r  e   at
           / \
          a   t
在擾亂這個字符串的過程中,我們可以挑選任何一個非葉節點,然後交換它的兩個子節點。

例如,如果我們挑選非葉節點 "gr" ,交換它的兩個子節點,將會產生擾亂字符串 "rgeat" 。

    rgeat
   /    \
  rg    eat
 / \    /  \
r   g  e   at
           / \
          a   t
我們將 "rgeat” 稱作 "great" 的一個擾亂字符串。

同樣地,如果我們繼續交換節點 "eat" 和 "at" 的子節點,將會產生另一個新的擾亂字符串 "rgtae" 。

    rgtae
   /    \
  rg    tae
 / \    /  \
r   g  ta  e
       / \
      t   a
我們將 "rgtae” 稱作 "great" 的一個擾亂字符串。

給出兩個長度相等的字符串 s1 和 s2,判斷 s2 是否是 s1 的擾亂字符串。

示例 1:

輸入: s1 = "great", s2 = "rgeat"
輸出: true
示例 2:

輸入: s1 = "abcde", s2 = "caebd"
輸出: false

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/scramble-string
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。

白話題目:
 

算法:

 

詳細解釋關注 B站  【C語言全代碼】學渣帶你刷Leetcode 不走丟 https://www.bilibili.com/video/BV1C7411y7gB

C語言完全代碼

//方法二:動態規劃算法
//1,遞歸是自頂向下處理,不斷將問題分解遞歸,複雜度高,超時
//2,用數組保存遞歸過程中的值,將處理問題的方式改爲 自底向上處理
//3,把 自頂向下 改成 自底向上 需要解決如何找到最小值的問題,即最先計算什麼
//4,遞歸函數傳遞過程中處理了三個元素 (i, j, len) 分別爲 s1下標,s2下標,分割長度
//5,使用動態數組 dp[i][j][l] 表示 &s1[i] 和 &s2[j] 長度爲 l 個字符是否爲擾亂字符串
//6,計算初始值 當 l=1 時 if(s1[i]==s2[j]) dp[i][j][1]=true
//7,三維的動態規劃數組不太好理解,可以先理解幾個例子
/*
以 great 和 rgeat 爲例
例1:
當 l == 2 時
dp[0][0][2] = (dp[0][0][1] && dp[1][1][1]) || (dp[0][1][1] && dp[1][0][1])
...
dp[3][3][2] = (dp[3][3][1] && dp[4][4][1]) || (dp[3][4][1] && dp[4][3][1])

當 l == 3 時
dp[0][0][3] = ((dp[0][0][1] && dp[1][1][2]) || (dp[0][2][1] && dp[1][0][2])) ||
              ((dp[0][0][2] && dp[2][2][1]) || (dp[0][1][2] && dp[2][0][1]))
...
dp[2][2][3] = ((dp[2][2][1] && dp[3][3][2]) || (dp[2][4][1] && dp[3][2][2])) ||
              ((dp[2][2][2] && dp[4][4][1]) || (dp[2][3][2] && dp[4][2][1]))
*/

bool isScramble(char * s1, char * s2){
    int     i           = 0;
    int     j           = 0;
    int     l           = 0;
    int     k           = 0;

    int     iLenS1      = strlen(s1);
    int     iLenS2      = strlen(s2);
    bool    bRet        = false;
    bool    dp[iLenS1][iLenS2][iLenS1 + 1];

    if((NULL == s1) || (NULL == s2) || (iLenS1 != iLenS2)) return false;
    
    //1,初始化動態規劃數組
    memset(dp, 0x00, sizeof(bool) * iLenS1 * iLenS2 * (iLenS1 + 1));
    for(i = 0; i < iLenS1; i++)
    {
        for(j = 0; j < iLenS2; j++)
        {
            if(s1[i] == s2[j])
            {
                dp[i][j][1] = true;
            }
        }
    }

    //2,動態規劃處理
    for(l = 2; l <= iLenS1; l++)
    {
        //依次處理分割長度
        for(i = 0; i <= iLenS1 - l; i++)
        {
            for(j = 0; j <= iLenS2 - l; j++)
            {
                //計算 dp[i][j][l] 的值, 需要判斷 (1, l) 範圍任一分割長度是否能判定爲擾亂字符串
                for(k = 1; k < l; k++)
                {
//                    printf("[1][i=%d][j=%d][l=%d][k=%d][%d][%d]\n", i, j, l, k, dp[i][j][k], dp[i + k][j + k][l - k]);
                    //判斷不交換節點
                    if((dp[i][j][k]) && (dp[i + k][j + k][l - k]))
                    {
                        dp[i][j][l] = true;
                        break;
                    }

//                    printf("[2][i=%d][j=%d][l=%d][k=%d][%d][%d]\n", i, j, l, k, dp[i][j + l - k][k], dp[i + k][j][l - k]);
                    //判斷交換節點
                    if((dp[i][j + l - k][k]) && (dp[i + k][j][l - k]))
                    {
                        dp[i][j][l] = true;
                        break;
                    }
                }
            }
        }
    }

    return dp[0][0][iLenS1];
}



/*
//方法一:遞歸法(超時)
//1,求最終解 fun(s1(0, len), s2(0, len)) 表示字符串s1,和s2是否匹配爲擾亂字符串
//2,遞歸算法
//3,按照字符串長度遍歷 k = (1, len) 
//4, fun(s1(0, len), s2(0, len)) = 
// (fun(s1(0, k), s2(0, k)) && fun(s1(k, len), s2(k, len))) || 
// (fun(s1(0, k), s2(len - k, len)) && fun(s1(k, len), s2(0, len - k)))

//遞歸函數
bool recursiveScramble(char* s1, char* s2, int len){
    int     i       = 0;
    bool    bRet    = false;

//    printf("[1][s1=%s][s2=%s][len=%d]\n", s1, s2, len);

    //1,結束處理
    if(len == 1)
    {
        if(s1[0] == s2[0])  return true;
    }
    else
    {
        //2,遍歷長度回溯處理
        for(i = 1; i < len; i++)
        {
            //不交換處理
            bRet = recursiveScramble(&s1[0], &s2[0], i);
//            printf("[2][s1=%s][s2=%s][i=%d][ret=%d]\n", &s1[0], &s2[0], i, bRet);
            if(bRet)
            {//great
                bRet &= recursiveScramble(&s1[i], &s2[i], len - i);
//                printf("[3][s1=%s][s2=%s][len=%d][ret=%d]\n", &s1[i], &s2[i], len - i, bRet);
                if(bRet) return true;
            }

            //交換處理
            bRet = recursiveScramble(&s1[0], &s2[len - i], i);
//            printf("[4][s1=%s][s2=%s][len=%d][ret=%d]\n", &s1[0], &s2[len - i], i, bRet);
            if(bRet)
            {//great
                bRet &= recursiveScramble(&s1[i], &s2[0], len - i);
//                printf("[5][s1=%s][s2=%s][len=%d][ret=%d]\n", &s1[i], &s2[0], len - i, bRet);
                if(bRet) return true;
            }
        }
    }

    return bRet;
}

bool isScramble(char * s1, char * s2){
    int     iLenS1      = strlen(s1);
    int     iLenS2      = strlen(s2);
    bool    bRet        = false;

    if((NULL == s1) || (NULL == s2) || (iLenS1 != iLenS2)) return false;

    bRet = recursiveScramble(s1, s2, iLenS1);

    return bRet;
}
*/

 

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