Skip to content

leetcode_OJ WC78 解題心得

  • Contest time: Apr 1, 2018

PA. 811. Subdomain Visit Count substr + map 活用水題

  • 思路:簡單的水題,用substr裁切網域名稱後再hash到統計數字,以stoi函數來將string的數字轉成統計值
    #define FORI(n) for(int i = 0; i < n; ++ i)
    #define pb push_back
    class Solution
    {
    public:
        vector<string> subdomainVisits(vector<string>& cpdomains)
        {
            map<string ,int> mymap;
            vector<vector <int> > dotpos;
            vector<int> visit; //each domain visit
            dotpos.resize(cpdomains.size());
            //cpdomains[i].size() - 1
            FORI(cpdomains.size())
            {
                for(int j = cpdomains[i].size() - 1; j >= 0; j--)
                {
                    if(cpdomains[i][j] == '.')
                    {
                        dotpos[i].pb(j);
                    }
                    else if(cpdomains[i][j] == ' ')
                    {
                        dotpos[i].pb(j);
                        break;
                    }
                }
            } //subdomain pos
            string tmp;
            FORI(cpdomains.size())
            {
                for(int j = 0; j < cpdomains[i].size(); j++)
                {
                    if(cpdomains[i][j] == ' ')
                    {
                        tmp = cpdomains[i].substr(0,j + 1);
                        int tmp2 = stoi(tmp);
                        visit.pb(tmp2);
                        break;
                    }
                }
            } //times
            int poscnt = 0;
            FORI(cpdomains.size())
            {
                for(int j = 0; j < dotpos[i].size(); j++)
                {
                    tmp = cpdomains[i].substr(dotpos[i][j] + 1, cpdomains[i].size() - dotpos[i][j] + 1);
                    mymap[tmp] += visit[i];
                }
            }//accumulate
    
            vector<string> res;
            string timestr;
            for(map<string, int>::iterator it = mymap.begin(); it != mymap.end(); ++it)
            {
                timestr = to_string(it->second);
                res.pb(timestr + " " + it->first);
            }
            return res;
        }
    };
    

PB.809. Expressive Words 字串雙指標推理觀察題

  • 思路:不算難的題目,只是題目有點含糊不好懂,實際上意思為 若以word的char來延伸成功(延伸成功的定義為:並列的char達到三個以上)"並且" 經由成功延伸的char 最後能達到目標字串,便是一個expressive word轉換 例如:dddiiiinnssssssoooo 若為目標字串 則 dinnsoo 可以 因為 d+dd(延伸達到3) i+iii(延伸達到4) nn=nn s+sssss(延伸達到6) o+ooo(延伸達到4) 最後能組成目標字串 ddinnso也可(當初以為要dd視為一組來延神 ,而ddd / dd 只有1.5倍不行,然而題目只要求延伸,因此也能用單一字元湊成,是故以單一字元延伸是一種保險的作法)

又如 ddinsoo便不行,乃是於 n+n只延伸了兩次,無法達陣,因此勢必無法做成原本的目標字串而放棄。

用上述的想法便能寫出以下ac代碼

#define FORI(n) for(int i = 0; i < n; ++ i)
#define pb push_back
class Solution
{
public:
    int expressiveWords(string str, vector<string>& words)
    {
        int res = 0, can = 0, cnt = 0, total_len = 0, extend_len = 0, group_len;
        for(int i = 0;i < words.size();i++)
        {
            can = 1; //can --> 可延伸湊出結果
            int k = 0;
            total_len = words[i].size(); //第i個檢測word的長度
            for(int j = 0;j < words[i].size();)
            {
                extend_len = 0;
                group_len = 1;
                if(words[i][j] != str[k])
                {
                    can = 0; //若有不一樣的,勢必無法湊成,
                    break;
                }
                else
                {
                    while(j != words[i].size() - 1 && words[i][j + 1] == words[i][j]) //找出在word中,相連一樣的組成一群的長度
                    {
                        j++;
                        group_len++;
                    }
                    while(1) //able to extend
                    {
                        if(words[i][j] == str[k])//延伸
                        {
                            k++;
                            extend_len++;
                        }
                        else //發現不一樣後跳出
                        {
                            // can = 0; 這個can = 0不可以加,因為這是再延深後判斷跳出的條件,並不是發現mismatch
                            break;
                        }
                    }

                    //last character extend
                    while(k < str.size() && j == words[i].size()-1) //結尾特例,繼續延伸
                    {
                        if(words[i][j] == str[k]) //延伸
                        {
                            k++;
                            extend_len++;
                        }
                        else //發現不一樣後跳出
                        {
                            can = 0; //在此的can 便要加入 = 0 例如 target = abcd 但是 word = abc 而 此時j會卡在size - 1 之後k繼續走到d發現不一樣便是無法組成
                            break;
                        }
                    }

                    if(extend_len < group_len) //若延伸的長度小於原本長度也不行
                    {
                        can = 0;
                        break;
                    }

                    if(extend_len >= 3) //if extend, should >=3 (as a group per unit)
                    {
                        total_len += extend_len - group_len ; // aa延伸成 aaaa 延伸的長度為 2 而非 4 故要扣除本身群組長度
                    }
                    j++;
                }
            }
            if(total_len != str.size()) //若最後依然長度附等,也不符合要求,故can=0
            {
                can = 0;
            }
            if(can)
            {
                res++;
            }
        }
        return res;
    }
};

PC. 808. Soup Servings 有點難觀察出規律的動態規劃題(施工中)

  • 思路:以每25毫升為單位切割,因此先把a b湯種的份量/25化繁為簡。

    接著,以dp表示『已經消費的湯種份量』 a湯種為row b為col,由於每一格均代表消耗的份量,因此可以採用由底層推上來的方式,將每一格由之前的四項點推得,並且逐步構築到serve份。

    而猶如題目所說,同時讓ab湯種耗盡時,需要乘上0.5的係數,而耗盡a湯種,因為是目標,故乘上1係數,然而耗盡b湯種並不是我們所要的,故乘上0係數

    如下查看每一種消費(實際上是從0 0開始看『已經』消耗的湯種份量,慢慢疊到serve份,需注意要將serve + 1來作為dp方陣的因在於我們要消耗到0份而非1份,因此在dp表格必須 + 1作為初始化的大小邊界,最後迴圈也跑到等於serve才停下,而非小於serve

以下為迭代版本的程式碼

if(i - 4 <= 0 && j <=0)
{
    dir1 = 0.5;
}
else if(i - 4 <= 0)
{
    dir1 = 1;
}
else if(j <= 0)
{
    dir1 = 0;
}
else
{
    dir1 = dp[i - 4][j];
}

(在題目以下的每個回圈判斷式便可以看到,詳細分析請見程式碼註解)

class Solution
{
public:
    double soupServings(int all)
    {
        if(all > 6000) //monotonically increasing since A is always used more than B. (by empirical method)
            return 1.0;

        int serve = ceil(all / 25.0) ; //25 ml as a serving unit,
        //一定要用ceil因為即便是沒有滿25ml也要完整的處理完畢,故得用ceil來將未滿一單位的湯種處理,既有的cpp除法會捨去
        vector<vector <double> > dp(serve + 1, vector<double>(serve + 1, 0)); //each grid represent the rest amount(unit) of a and be which //comes to here
        //A row, B col
        double dir1, dir2, dir3, dir4;
        for(int i = 0; i <= serve; i++)
        {
            for(int j = 0; j <= serve; j++)
            {
                if(i - 4 <= 0 && j <=0)
                {
                    dir1 = 0.5;
                }
                else if(i - 4 <= 0)
                {
                    dir1 = 1;
                }
                else if(j <= 0)
                {
                    dir1 = 0;
                }
                else
                {
                    dir1 = dp[i - 4][j];
                }

                if(i - 3 <= 0 && j - 1 <= 0)
                {
                    dir2 = 0.5;
                }
                else if(i - 3 <= 0)
                {
                    dir2 = 1;
                }
                else if(j - 1 <= 0)
                {
                    dir2 = 0;
                }
                else
                {
                    dir2 = dp[i - 3][j - 1];
                }


                if(i - 2 <= 0 && j - 2 <= 0)
                {
                    dir3 = 0.5;
                }
                else if(i - 2 <= 0)
                {
                    dir3 = 1;
                }
                else if(j - 2 <= 0)
                {
                    dir3 = 0;
                }
                else
                {
                    dir3 = dp[i - 2][j - 2];
                }


                if(i - 1 <= 0 && j - 3 <= 0)
                {
                    dir4 = 0.5;
                }
                else if(i - 1 <= 0)
                {
                    dir4 = 1;
                }
                else if(j - 3 <= 0)
                {
                    dir4 = 0;
                }
                else
                {
                    dir4 = dp[i - 1][j - 3];
                }
                dp[i][j] = 0.25 * (dir1 + dir2 + dir3 + dir4);
            }
        }
        return dp[serve][serve];
    }
};