Skip to content

leetcode_OJ WC75 解題心得

  • Contest time: Mar 11, 2018

眼睛發炎,打扣途中頗不舒服,只有快速解出PA後,PB DFS沒寫好不斷WA,PD用暴力解然並卵TLE,就,寫個網誌來檢討吧

PA. 796. Rotate String 簡單字串題

  • 思路:水題不解釋
    #define FORI(n) for(int i = 0; i < n; ++ i)
    class Solution
    {
    public:
        bool rotateString(string aa, string bb)
        {
            string tmp=aa;
            string tmp2;
            FORI(aa.size())
            {
                tmp2=tmp[0];
                tmp = tmp.substr(1,aa.size()-1);
                tmp+=tmp2;
                if(tmp == bb)
                    return 1;
            }
            return 0;
        }
    };
    

PB. 797. ALl path from src to dst 圖論題,起終點所有可能路徑

從起點到終點的所有路徑,圖論演算法經典題目!!!!!!!!!!!!!!!!!!!!!

  • 思路:dfs深度優先搜索

這個是WA的代碼,總會有些case沒有找到,因為在output deg那裡的邏輯些許錯誤

#define FORI(n) for(int i = 0; i < n; ++ i)
class Solution
{
public:
    vector<vector<int>> allPathsSourceTarget(vector<vector<int>>& graph)
    {

        int target = 0;
        int pos = 0, total_size = 0;
        vector<int> res_part, output_deg;
        output_deg.resize(graph.size());
        vector<vector<int>> final_res;
        FORI(graph.size())
        {
            if(graph[i].size()==0)
            {
                target = i;
            }
            else
            {
                total_size+=graph[i].size();
                output_deg[i] = graph[i].size();
            }
        }
        int visited = 0, i=0, tmp, undone = 1;
        while(visited != total_size)
        {
            res_part.push_back(pos);
            if(output_deg[pos])
            {
                tmp = pos;
                pos = graph[pos][output_deg[pos]-1];
                output_deg[tmp]--;
                visited++;
            }
            else
            {
                FORI(output_deg.size())
                {
                    if(output_deg[i])
                        pos = output_deg[i];
                }
            }
            if(graph[pos].size()==0)
            {
                pos = 0;
                res_part.push_back(target);
                final_res.push_back(res_part);
                res_part.clear();
            }
        }
        return final_res;
    }

};

這個是正確解法的代碼,使用的演算法便是:DFS深度優先搜索,以找出起終點的所有路徑
Geekforgeeks reference

weibo weibo的作法採用非遞迴做法
1.選取起點
2.移動,移到的點把它標記為走訪過,若該點不是終點,則擴散查找周圍『還沒有走過的點』
3.走到了終點之後,『退回上一步』,也是最重要的一個步驟,因為還有可能有其他路徑,故從終點的上一個步驟
4.下面的代碼中,原本44行的return寫上後會造成答案減少,原因在於做backtrace的時候,退回包刮終點也要標記為沒有走訪過, 如果終點仍然標記為走訪過,那麼之後第二條路徑要走到終點的時候便會看到終點已經走訪過,便不再向前走去終點,而導致結果不齊全

#define FORI(n) for(int i = 0; i < n; ++ i)
class Solution
{
public:
    vector<vector <int>>final_res;
    vector<int>res, visited;
    stack<int> traversed_path;
    vector<vector<int>> allPathsSourceTarget(vector<vector<int>>& graph) //graph in adjacency list
    {
        int dst;
        FORI(graph.size())
        {
            if(graph[i].size()==0)
            {
                dst = i;
            }
            visited.push_back(false);
        }
        dfs(0,dst,res,graph);
        return final_res;
    }
    void dfs(int cur_node, int dst, vector<int> res, vector<vector<int>> graph)
    {

        traversed_path.push(cur_node);
        visited[cur_node] = true;
        if(cur_node == dst)
        {

            stack<int> copied_stk = traversed_path;
            while(copied_stk.size())
            {
                res.push_back(copied_stk.top());
                copied_stk.pop();
            }
            reverse(res.begin(), res.end());

            final_res.push_back(res);
            res.clear();
            //return ;
        }
        else
        {

            FORI(graph[cur_node].size())
            {
                if(!visited[graph[cur_node][i]])
                {
                    dfs(graph[cur_node][i], dst, res, graph);
                }
            }
        }
        //back trace if there will be still some nodes have to be visited but now path are blocked since adj nodes are marked visited
        visited[cur_node] = false;
        cur_node = traversed_path.top();
        traversed_path.pop();
    }

};

PC. 799. Champagne Tower 數學規劃與觀察題

  • 思路:雖然題目有點嚇人,但只是個障眼法,剛開始想說一次在第一盃添加一次,再讓每一次的流水依序往下流竄,如果有杯子已經滿水位,就將row++ 再度往下流竄,直到底,然不僅時間複雜度太高也在第260個測資WA了

事實上,只要先將最高的那一杯水,任意裝滿他的pour量,先不用在乎是否已經超出滿水位,只要先把多出的水依序流竄,並且左右均分即可,而會多出的水位就是 當前水位 - 一杯水 之後再將這個堆出的水位評分給樓下兩杯即可。 很智障的是 以為樓下兩杯是 row+1 col-1 and row+1 col+1 利馬拿了一個RE,實際上應該是col col+1啦w

class Solution
{
public:
    double champagneTower(int poured, int query_row, int query_glass)
    {
        vector<vector <double > > cups;
        cups.resize(101); //padding
        for(int i=0;i<101;i++)
        {
            for(int j=0;j<=i;j++)
            {
                cups[i].push_back(0.0);
            }
        }
        cups[0][0] = poured;
        for(int i=0;i<100;i++)
        {
            for(int j=0;j<=i;j++)
            {
                if(cups[i][j] >= 1.0)
                {
                    cups[i+1][j] += (cups[i][j] - 1.0) / 2.0 ;
                    cups[i+1][j+1] += (cups[i][j] - 1.0) / 2.0 ;
                    cups[i][j] = 1.0;
                }
            }
        }
        return cups[query_row][query_glass];
    }
};

PD. 800. Smallest rotation with highest score 數學推理+區間查詢線性優化O(N)

此題的時間複雜度一定要在O(N),必須使用區間查詢算法,大神室友馬上想到線段樹segment tree查找 區間查詢算法概念,從暴力到NlogN 到N
* 思路,可以看出有兩種情形,一種是本來就會得分的(value <= index),一種是還沒有得分的 else
第一類型
首先第一種本來就可以得分,例如[2,3,1,4,0]中的1 , 0,向右移動自然可以得分,所以他的右邊可以的步數便是[index+1(直接向左移動到最右側(超過後重新從結尾回來),必然符合的開外掛模式),len-1(移動到他下一個)] 以及[0(不動),index - value(例如上面的1在2 至多移動到1的位置,也就是 2 - 1 一步)]
第二類型
而另外一種當前無法得分的,便要[index+1 (開外掛移到最右邊), total_len - (value - index)(繼續移動,value - index 代表與最大移動次數的相差,也就是它必須向右移動val - index這個差值才有分,向右移動的至少次數,換過來講用 len 來扣除就是向左移動的最大次數)]

求出每一個數字應該有的區間,把他們映射到區間查詢段,使用python的pair表示開始和結束

for index, value in enumerate(arr):
    if index < value: #one segment for this ones
        pair.append([index + 1 ,total_len - (value - index)]) #segment start and end
    else: #two segments for this one
        pair.append([index + 1, total_len - 1])
        pair.append([0, index - value])

最後找到prefix sum (加總到此時的總和),思緒見註解

segment_query = [0] * (total_len + 1)  #aux arrat for the prefix sum, segment query
for i in range (len(pair)): #+1 padding
    segment_query[pair[i][0]] += 1 #go in the interval, overlapping with all the other segment
    segment_query[pair[i][1] + 1] -= 1 #leave the interval, cancelling the infulence of segment overlapping

整體AC代碼如下

class Solution:
    def bestRotation(self, arr):
        best = 0
        shift = 0
        total_len = len(arr)
        #start_pos_arr = []
        pair = []
        #initial the start_pos_arr to record the starting position of the given array
        #initial score
        for index, value in enumerate(arr):
            if index < value: #one segment for this ones
                pair.append([index + 1 ,total_len - (value - index)]) #segment start and end
            else: #two segments for this one
                pair.append([index + 1, total_len - 1])
                pair.append([0, index - value])


        segment_query = [0] * (total_len + 1)  #aux arrat for the prefix sum, segment query
        for i in range (len(pair)): #+1 padding
            segment_query[pair[i][0]] += 1 #go in the interval, overlapping with all the other segment
            segment_query[pair[i][1] + 1] -= 1 #leave the interval, cancelling the infulence of segment overlapping

        cur_pts = 0
        for i in range (len(segment_query)):
             cur_pts += segment_query[i]
             if( cur_pts > best):
                 best = cur_pts
                 shift = i

        return shift