1. 程式人生 > 實用技巧 >LeetCode周賽#206

LeetCode周賽#206

1583. 統計不開心的朋友 #模擬 #暴力

題目連結

題意

n為朋友,對每位朋友ipreference[i]包含 按親密度從大到小 的朋友編號。

朋友們會被分為若干對,配對情況由pairs陣列給出,即pair[i]={xi, yi}表示xiyi相互配對。

xy相互配對且uv相互配對的情況下,如果同時滿足下面兩個條件,x就會不高興

  • x->u親密度 大於 x->y
  • u->x親密度 大於 u->v

分析

初看題目,我以為一旦滿足上述兩條件,不但x不高興,u也會不高興。然而,這是錯的。

對於資料6, preferences=[[1,4,3,2,5],[0,5,4,3,2],[3,0,1,5,4],[2,1,4,0,5],[2,1,0,3,5],[3,4,2,0,1]], pairs = [[3,1],[2,0],[5,4]]

,只有5號是高興的,這是因為5號對4號親密度太高(rank=4),5號只能去找1(rank=5),然而1號對3號的親密度更高(rank=5),被3號鎖住,因而5是高興的。

由此,我們不應該遍歷pairs,而是將pairs中的配對情況記錄到每個人身上,再遍歷每個人,檢查是否不開心。

下面程式碼中rank[i][j]代表i號對j號的親密度。而mypair[i]代表ipair中配對的另一個人編號。

class Solution {
private:
    int rank[505][505], mypair[505];
public:
    bool Judge(int cur, int n){ //判斷是否不開心
        int p = mypair[cur];
        for (int i = 0; i < n; i++){
            if(rank[cur][p] < rank[cur][i]
            && rank[i][mypair[i]] < rank[i][cur]) //按照題目要求
                return true;
        }
        return false;
    }
    int unhappyFriends(int n, vector<vector<int>>& preferences, vector<vector<int>>& pairs) {
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n - 1; j++) 
                rank[i][preferences[i][j]] = n - j; //存下i的朋友親密度
        for (int i = 0; i < n / 2; i ++){ //將每對pair中兩人對應隊友記錄下來
            mypair[pairs[i][0]] = pairs[i][1]; 
            mypair[pairs[i][1]] = pairs[i][0];
        }
        int ans = 0;
        for(int i = 0; i < n; i++) 
            if(Judge(i, n)) ans++;
        return ans;
    }
};

1585. 檢查字串是否可以通過排序子字串得到另一個字串 #暴力 #排序思想 #模擬

題目連結

題意

給定字串st,可通過若干次的下述操作將s轉化為t——選擇s中一個非空子字串並將它包含的字元就地升序排序。現要你判斷s通過這些操作能否得到t。其中子字串定義為一個字串中連續的若干字元。

分析

更詳細的證明過程參考零神的題解

模擬st的過程,對t串一個個字元進行考慮。首先考慮t[0]t串的首字元)在s串中首位置,記為s[t_0](=t[0])。我們怎麼知道字元s[t_0]能否通過排序使其放到s首位呢?只有當s[t_0]都小於s[0],s[1],...,s[t_0 - 1]這些元素,即比s[t_0]小的元素 都在s[t_0]

的右側,這時候s[t_0]有機會通過排序將原來位置降到s的首位置。當我們比較完,確定滿足該條件時,s[t_0]以後不再考慮,轉而考慮下一字元t[1],找到在s中對應的 最前位置s[t_i],判斷s[t_i]能否移動到s中的第1個位置…..

如何實現?我們為10個數字的每個數字都準備一個佇列,用來儲存該數字在s串中的位置。為什麼要用佇列?因為我們在檢查cur前面的數字是否在cur左側時,只需要用查詢數字0,1,...,cur-1的當前一個位置即可,若檢查不出,說明可以將cur搬到前面,接下來直接將該cur的最新下標排除即可,模擬排序子過程。

class Solution {
public:
    bool isTransformable(string s, string t) {
        vector< queue<int> > pos(10);
        for (int i = 0; i < s.length(); i++)
            pos[s[i] - '0'].push(i); //存下每一種數字在s串中的位置
        for (int i = 0; i < t.length(); i++){ //遍歷t串中每一個字元
            int cur = t[i] - '0';
            if(pos[cur].empty()) //說明s串字元數量與t串不相等,顯然無法滿足題意
                return false;
            for (int j = 0; j <= cur; j++){ //檢查s串中 比t[i]小 的字元 所在的下標
                if(!pos[j].empty() && pos[j].front() < pos[cur].front())
                    return false; 
                //如果t串中t[i]的左邊,存在一個比t[i]還小的字元,顯然不能將t[i]冒泡到前面
            }
            pos[cur].pop(); //即時更新數字cur的下標
        }
        return true;
    }
};