leetCode進階算法題+解析(七十四)

終于可以往后趕趕進度了,這周開始寫下周的筆記盏触,美滋滋~~嘿嘿

香檳塔

題目:我們把玻璃杯擺成金字塔的形狀愉耙,其中第一層有1個玻璃杯贮尉,第二層有2個,依次類推到第100層朴沿,每個玻璃杯(250ml)將盛有香檳猜谚。從頂層的第一個玻璃杯開始傾倒一些香檳,當頂層的杯子滿了赌渣,任何溢出的香檳都會立刻等流量的流向左右兩側(cè)的玻璃杯魏铅。當左右兩邊的杯子也滿了,就會等流量的流向它們左右兩邊的杯子坚芜,依次類推览芳。(當最底層的玻璃杯滿了,香檳會流到地板上)例如鸿竖,在傾倒一杯香檳后沧竟,最頂層的玻璃杯滿了。傾倒了兩杯香檳后缚忧,第二層的兩個玻璃杯各自盛放一半的香檳悟泵。在倒三杯香檳后,第二層的香檳滿了 - 此時總共有三個滿的玻璃杯闪水。在倒第四杯后糕非,第三層中間的玻璃杯盛放了一半的香檳,他兩邊的玻璃杯各自盛放了四分之一的香檳,如下圖所示朽肥。
題目截圖

現(xiàn)在當傾倒了非負整數(shù)杯香檳后禁筏,返回第 i 行 j 個玻璃杯所盛放的香檳占玻璃杯容積的比例(i 和 j都從0開始)。
示例 1:
輸入: poured(傾倒香檳總杯數(shù)) = 1, query_glass(杯子的位置數(shù)) = 1, query_row(行數(shù)) = 1
輸出: 0.0
解釋: 我們在頂層(下標是(0鞠呈,0))倒了一杯香檳后,沒有溢出右钾,因此所有在頂層以下的玻璃杯都是空的蚁吝。
示例 2:
輸入: poured(傾倒香檳總杯數(shù)) = 2, query_glass(杯子的位置數(shù)) = 1, query_row(行數(shù)) = 1
輸出: 0.5
解釋: 我們在頂層(下標是(0,0)倒了兩杯香檳后舀射,有一杯量的香檳將從頂層溢出窘茁,位于(1,0)的玻璃杯和(1脆烟,1)的玻璃杯平分了這一杯香檳山林,所以每個玻璃杯有一半的香檳。
注意:
poured 的范圍[0, 10 ^ 9]邢羔。
query_glass 和query_row 的范圍 [0, 99]驼抹。

思路:這個題其實做起來應該不難。首先我的想法是用數(shù)組來表示拜鹤。i+1層數(shù)組框冀。然后數(shù)組的數(shù)目是從1到i+1。然后有一點是其實每一個上面的數(shù)組都會流向下一行的同等下標和+1下標敏簿。這個確定了之后只要順序走數(shù)字變化就行了夯到,我去寫下代碼嫂沉。
第一版本代碼:

class Solution {
    public double champagneTower(int poured, int query_row, int query_glass) {
        double[][] d = new double[query_row+1][];
        d[0] = new double[]{poured};
        for(int i = 1;i<=query_row;i++) {
            d[i] = new double[i+1];
            for(int j = 0;j<d[i].length-1;j++) {
                double cur = d[i-1][j]-1;//只有滿了才有溢出
                if(cur<0) continue;
                d[i][j] += cur/2;
                d[i][j+1] += cur/2;
            }
        }
        return d[query_row][query_glass]>1?1.0:d[query_row][query_glass];
    }
}

性能比較不錯,思路也很順。沒啥難點百侧。就是從上往下判斷。然后溢出了才往左右流等限。重點是如果當前杯子沒溢出則不操作屋彪,第一遍我把這個判斷漏掉了,結(jié)果測試發(fā)現(xiàn)有負數(shù)才補上的握玛,當然了這個也是因為我的馬虎大意猜煮。我去瞅一眼性能第一的代碼,不出意外這個題就過了:

class Solution {
    public double champagneTower(int poured, int query_row, int query_glass) {
        double[] wine = new double[query_row+1];
        wine[0] = poured;
        for (int i = 1;i <= query_row;i++) {
            for (int j = i;j >= 0;j--) {
                if (wine[j] > 1.0) {
                    double out = (wine[j]-1.0)/2.0;
                    wine[j+1]+=out;
                    wine[j] = out;
                }
                else {
                    wine[j] = 0.;
                }
            }
        }
        return Math.min(1, wine[query_glass]);
    }
}

這個應該算是狀態(tài)壓縮了吧败许。我是用二維數(shù)組一層一層表示王带,人家是一個數(shù)組直接壓縮展示,而思路上沒什么不同市殷,直接過了愕撰。

使序列遞增的最少交換次數(shù)

題目:我們有兩個長度相等且不為空的整型數(shù)組 A 和 B 。我們可以交換 A[i] 和 B[i] 的元素。注意這兩個元素在各自的序列中應該處于相同的位置搞挣。交換過一些元素之后带迟,數(shù)組 A 和 B 都應該是嚴格遞增的(數(shù)組嚴格遞增的條件僅為A[0] < A[1] < A[2] < ... < A[A.length - 1])。給定數(shù)組 A 和 B 囱桨,請返回使得兩個數(shù)組均保持嚴格遞增狀態(tài)的最小交換次數(shù)仓犬。假設給定的輸入總是有效的。

示例:
輸入: A = [1,3,5,4], B = [1,2,3,7]
輸出: 1
解釋:
交換 A[3] 和 B[3] 后舍肠,兩個數(shù)組如下:
A = [1, 3, 5, 7] 搀继, B = [1, 2, 3, 4]
兩個數(shù)組均為嚴格遞增的。
注意:
A, B 兩個數(shù)組的長度總是相等的翠语,且長度的范圍為 [1, 1000]叽躯。
A[i], B[i] 均為 [0, 2000]區(qū)間內(nèi)的整數(shù)。

思路:這個題的標簽是動態(tài)規(guī)劃肌括,但是具體怎么用dp實現(xiàn)呢点骑,我去尋思尋思遞推公式。
在群友的指點下有了大概的思路:那就是每一個值都有兩個狀態(tài):換谍夭,不換黑滴。也就是01背包問題。然後繼這兩個狀態(tài)紧索,其中有必須交換的節(jié)點和非必須交換的節(jié)點跷跪。而且因為條件一定滿足,所以所有的數(shù)據(jù)滿足下面二者之一的規(guī)律(也可能兩個都滿足):

  • A[i]>A[i-1] && B[i]>B[i-1] 這種情況是兩者都遞增
  • A[i]>B[i-1] && B[i]>A[i-1] 這種情況發(fā)生在某列不遞增齐板,需要交換
    首先兩者都滿足的話吵瞻,則可換可不換,換不換看情況甘磨。(因為可能當前兩列都滿足橡羞,但是后面的3列不滿足,所以為了最佳換這兩列)
    其次如果滿足條件1济舆,仍然是可換可不換卿泽,原因和上面一樣
    最后如果只滿足條件2,說明某列不遞增滋觉,要么當前要么上一個签夭,必須換一個!
    有了以上兩點和三種情況椎侠,有了如下代碼:
    第一版本代碼:
class Solution {
    public int minSwap(int[] A, int[] B) {
        int len = A.length;
        //dp0代表換第租,dp1代表不換
        int[][] dp = new int[len][2];
        dp[0][0] = 1;//如果第一個元素就換,則dp[0][0] == 1
        //因為一定滿足可交換的情況我纪,所以所有元素必然滿足一下兩種條件或者兩種都滿足:
        //1. A[i]>A[i-1] && B[i]>B[i-1]   這種情況是兩者都遞增
        //2. A[i]>B[i-1] && B[i]>A[i-1]   這種情況發(fā)生在某列不遞增丐吓,需要交換了
        for(int i = 1;i<len;i++){
            if(A[i]>A[i-1] && B[i]>B[i-1] && A[i]>B[i-1] && B[i]>A[i-1]){
                dp[i][0] = Math.min(dp[i-1][0],dp[i-1][1])+1;
                dp[i][1] = Math.min(dp[i-1][0],dp[i-1][1]);
            }else if(A[i]>B[i-1] && B[i]>A[i-1]){//到這說明必然交換,只不過是交換上一個還是當前
                dp[i][0] = dp[i-1][1]+1;//交換當前
                dp[i][1] = dp[i-1][0];//交換上一個
            }else{//到這說明可換可不換粘衬,隨便找個
                dp[i][0] = dp[i-1][0]+1;
                dp[i][1] = dp[i-1][1];
            }
        }
        return Math.min(dp[len-1][0],dp[len-1][1]);
    }
}

其實這個題怎么說呢稚新,我一直都覺得dp簡直不是我這個小腦瓜能看明白的枷莉。做過的題目還有點頭緒,遇到不認識的就一臉懵比噪裕。尤其是只要涉及到二維dp(這個題目也是分狀態(tài)膳音,也可以算是二維dp)就掉頭發(fā)祭陷。兵志。01背包當年(也就是去年)看過教程和視頻想罕,結(jié)果硬生生的套不到題目上按价。除了多練練還能怎么辦呢~哎楼镐。我這個雖然做出來了但是性能不是很好鸠蚪,而且我個人也覺得可以優(yōu)化茅信,起碼可以壓縮成兩個量而不是數(shù)組妖谴。因為本質(zhì)上只用到了上一個的兩個狀態(tài)值膝舅。我優(yōu)化試一下:

class Solution {
    public int minSwap(int[] A, int[] B) {
        int len = A.length;
        int h = 1;//第一個元素換是1
        int bh = 0;//不換則0
        //因為一定滿足可交換的情況仍稀,所以所有元素必然滿足一下兩種條件或者兩種都滿足:
        //1. A[i]>A[i-1] && B[i]>B[i-1]   這種情況是兩者都遞增
        //2. A[i]>B[i-1] && B[i]>A[i-1]   這種情況發(fā)生在某列不遞增,需要交換了
        for(int i = 1;i<len;i++){
            if(A[i]>A[i-1] && B[i]>B[i-1] && A[i]>B[i-1] && B[i]>A[i-1]){
                bh = Math.min(h,bh);
                h = bh+1;
            }else if(A[i]>B[i-1] && B[i]>A[i-1]){//到這說明必然交換享幽,只不過是交換上一個還是當前
                int temp = h;//這里要繞圈
                h = bh+1;//交換當前
                bh = temp;//交換上一個
            }else{//到這說明可換可不換值桩,隨便找個
                h += 1;
            }
        }
        return Math.min(h,bh);
    }
}

2ms,性能超過百分之九十三奔坟。自我滿足了咳秉。我直接去看看題解吧滴某。

class Solution {
    //801. 使序列遞增的最小交換次數(shù)
    public int minSwap(int[] A, int[] B) {
        int aMax=0;
        int aMin=0;
        int lastMax=-1;
        for(int i=0;i<A.length;i++){
            if(A[i]>B[i]){
                if(B[i]>lastMax){//兩種
                    aMax=Math.min(aMax, aMin);
                    aMin=1+aMax;
                }else{//一種霎奢,aMax
                    aMin=1+aMin;
                }
                lastMax=A[i];
            }else if(A[i]<B[i]){
                if(A[i]>lastMax){
                    aMin=Math.min(aMax, aMin);
                    aMax=1+aMin;
                }else{
                    aMax=1+aMax;
                }
                lastMax=B[i];
                
            }else{
                lastMax=A[i];
            }
        }
        return Math.min(aMax, aMin);
    }
}

性能第一的代碼。怎么說呢晤硕,我感覺可能是因為上兩種方法是我自己寫的舞箍,所以思路賊清晰疏橄。但是這個代碼是人家寫的捎迫,而且大大優(yōu)化過窄绒,所以勉強看懂了蛔翅,但是覺得易讀性來說還是我的好搁宾,哈哈。其實本來當前A元素,B元素膏燃,上一個A元素组哩,上一個B元素。四個值來判斷是哪種情況黍衙。但是這里是可以稍微簡化一點的位仁。比如上面的代碼聂抢,只用了三個量來判斷〗瘟粒總而言之精致的很但是沒那么直觀我注。這個題也就這樣了但骨,下一題奔缠。

找到最終的安全狀態(tài)

題目:在有向圖中校哎,從某個節(jié)點和每個轉(zhuǎn)向處開始出發(fā),沿著圖的有向邊走抱怔。如果到達的節(jié)點是終點(即它沒有連出的有向邊),則停止。如果從起始節(jié)點出發(fā)乍狐,最后必然能走到終點藕帜,就認為起始節(jié)點是 最終安全 的。更具體地說时甚,對于最終安全的起始節(jié)點而言,存在一個自然數(shù) k ,無論選擇沿哪條有向邊行走 ,走了不到 k 步后必能停止在一個終點上糠馆。返回一個由圖中所有最終安全的起始節(jié)點組成的數(shù)組作為答案又碌。答案數(shù)組中的元素應當按 升序 排列愤炸。該有向圖有 n 個節(jié)點掉奄,按 0 到 n - 1 編號,其中 n 是 graph 的節(jié)點數(shù)。圖以下述形式給出:graph[i] 是編號 j 節(jié)點的一個列表谍婉,滿足 (i, j) 是圖的一條有向邊镀迂。
題目截圖

輸入:graph = [[1,2],[2,3],[5],[0],[5],[],[]]
輸出:[2,4,5,6]
解釋:示意圖如上箱季。
示例 2:
輸入:graph = [[1,2,3,4],[1,2],[3,4],[0,4],[]]
輸出:[4]
提示:
n == graph.length
1 <= n <= 104
0 <= graph[i].legnth <= n
graph[i] 按嚴格遞增順序排列塌衰。
圖中可能包含自環(huán)。
圖中邊的數(shù)目在范圍 [1, 4 * 104] 內(nèi)获诈。

思路:這個題咋說呢。我目前的想法就是一個元素一個元素過挟冠,這個一定要標記。比如哪個元素成環(huán)了伪窖,那么下一個元素遇到他就直接pass。大概思路就這樣泥栖,我去代碼實現(xiàn)下試試簇宽。
第一版代碼ac是ac了,但是我覺得我可能做的反而復雜了吧享。先貼上代碼:

class Solution {
    Boolean[] d;
    public List<Integer> eventualSafeNodes(int[][] graph) {
        d = new Boolean[graph.length];
        List<Integer> ans = new ArrayList<>();
        for(int i = 0;i<graph.length;i++){
            if(graph[i].length == 0) d[i] = true;
        }
        for(int i = 0;i<graph.length;i++){
            if(d[i] == null) dfs(graph,new HashSet<>(),i);
            if(d[i] == true) ans.add(i);
        }
        return ans;
    }
    public void dfs(int[][] graph,Set<Integer> set,Integer temp){
        if(set.contains(temp)) {
            d[temp] = false;
            return;
        }
        set.add(temp);
        for(int i:graph[temp]){
            if(d[i] == null) dfs(graph,new HashSet<>(set),i);
            if(d[i] == false) {
                d[temp] = false;
                return;
            }
        }
        d[temp] = true;
        return;
    }
}

這個題思路上大差不差魏割,就是一個dfs和標記。我這里用了數(shù)組表示不同狀態(tài)钢颂、Boolean數(shù)組钞它,初始值null表示未知。false表示此元素無法全部到末尾殊鞭。true不表示此元素可以遭垛。遍歷的時候一個元素下一個中有false直接false。一個元素下一個有true不管操灿,有未知去判斷未知是什么锯仪。只有當一個元素的所有下一個元素都是true它本身才能是true。其實這個題隨著做我隨著發(fā)現(xiàn)可以換種寫法趾盐。比如用hash來表示庶喜。當前元素是Key,下一個是Value救鲤。然后順著路往下走久窟。依然可以標記、主要就是構圖的方法來實現(xiàn)應該也可以本缠。不過我覺得再怎么也沒這么直觀的性能好吧斥扛。
這個題暫時真的沒啥好思路了,我去看看性能第一的代碼:

class Solution {
    public List<Integer> eventualSafeNodes(int[][] graph) {
        int N = graph.length;
        int[] color = new int[N];
        List<Integer> ans = new ArrayList();

        for (int i = 0; i < N; ++i)
            if (dfs(i, color, graph))
                ans.add(i);
        return ans;
    }

    // colors: WHITE 0, GRAY 1, BLACK 2;
    public boolean dfs(int node, int[] color, int[][] graph) {
        if (color[node] > 0)
            return color[node] == 2;

        color[node] = 1;
        for (int nei: graph[node]) {
            if (color[node] == 2)
                continue;
            if (color[nei] == 1 || !dfs(nei, color, graph))
                return false;
        }

        color[node] = 2;
        return true;
    }
}

我可能是細節(jié)處理上的問題搓茬,或者說我用Boolean包裝類導致性能不好的犹赖?其實這個確實數(shù)組中元素表示三個狀態(tài),確實用int也可以搞定卷仑。不過我覺得還是要掙扎意思,照著差不多的思路我取用Boolean試試麸折。
修改版代碼:

class Solution {
    public List<Integer> eventualSafeNodes(int[][] graph) {
        Boolean[] d = new Boolean[graph.length];
        List<Integer> ans = new ArrayList<>();
        for(int i=0;i<graph.length;i++) if(dfs(graph,d,i)) ans.add(i);
        return ans;
    }
    public boolean dfs(int[][] graph,Boolean[] d,Integer temp){
         if(d[temp] != null) return d[temp];
         int[] cur = graph[temp];
         d[temp] = false;//先假裝當前值false锡凝。下次遇到這個就說明是環(huán)了
         for(int i : cur){
             if((d[i] != null && d[i] == false) || !dfs(graph,d,i)) return false;
         }
         d[temp] = true;
         return true;
    }
}

除了人家是int數(shù)組我是Boolean數(shù)組,別的差不多一樣一樣的垢啼,性能就硬生生是人家的2倍窜锯。果然最開始就尋思錯了张肾。哎
不過這個題起碼是很明確了。需要表示多個狀態(tài)的時候染色是一個很好的選擇锚扎。下一題吞瞪。

保持城市天際線

題目:在二維數(shù)組grid中,grid[i][j]代表位于某處的建筑物的高度驾孔。 我們被允許增加任何數(shù)量(不同建筑物的數(shù)量可能不同)的建筑物的高度芍秆。 高度 0 也被認為是建筑物。最后翠勉,從新數(shù)組的所有四個方向(即頂部妖啥,底部,左側(cè)和右側(cè))觀看的“天際線”必須與原始數(shù)組的天際線相同对碌。 城市的天際線是從遠處觀看時荆虱,由所有建筑物形成的矩形的外部輪廓。 請看下面的例子朽们。建筑物高度可以增加的最大總和是多少怀读?

例子:
輸入: grid = [[3,0,8,4],[2,4,5,7],[9,2,6,3],[0,3,1,0]]
輸出: 35
解釋:
The grid is:
[ [3, 0, 8, 4],
[2, 4, 5, 7],
[9, 2, 6, 3],
[0, 3, 1, 0] ]
從數(shù)組豎直方向(即頂部,底部)看“天際線”是:[9, 4, 8, 7]
從水平水平方向(即左側(cè)骑脱,右側(cè))看“天際線”是:[8, 7, 9, 3]
在不影響天際線的情況下對建筑物進行增高后愿吹,新數(shù)組如下:
gridNew = [ [8, 4, 8, 7],
[7, 4, 7, 7],
[9, 4, 8, 7],
[3, 3, 3, 3] ]
說明:
1 < grid.length = grid[0].length <= 50。
grid[i][j] 的高度范圍是: [0, 100]惜姐。
一座建筑物占據(jù)一個grid[i][j]:換言之犁跪,它們是 1 x 1 x grid[i][j] 的長方體。

思路:講真歹袁,看完這個題目我只想說:medium和medium是不一樣的坷衍。看前兩道題条舔,又是dp狀態(tài)壓縮枫耳,又是染色一個值表示三種狀態(tài)。再看看這道題孟抗。簡單來說就是當前行列的最大值中的最小值迁杨。思路很清晰。我去實現(xiàn)了凄硼。
直接貼代碼:

class Solution {
    public int maxIncreaseKeepingSkyline(int[][] grid) {
        int len = grid.length;
        int[] r = new int[len];
        int[] c = new int[len];
        for(int i = 0;i<len;i++){
            for(int j = 0;j<len;j++){
                r[i] = Math.max(r[i],grid[i][j]);
                c[i] = Math.max(c[i],grid[j][i]);
            }
        }
        int ans = 0;
        for(int i = 0;i<len;i++){
            for(int j = 0;j<len;j++){
                ans += Math.min(r[i],c[j])-grid[i][j];
            }
        }
        return ans;
    }
}

因為這個性能超過百分百了铅协,所以我也不看題解了,感覺思路沒問題摊沉,處理上因為比較簡單也沒啥好說的狐史。這個題就這樣了。下一題。

情感豐富的文字

題目:有時候人們會用重復寫一些字母來表示額外的感受骏全,比如 "hello" -> "heeellooo", "hi" -> "hiii"苍柏。我們將相鄰字母都相同的一串字符定義為相同字母組,例如:"h", "eee", "ll", "ooo"姜贡。對于一個給定的字符串 S 试吁,如果另一個單詞能夠通過將一些字母組擴張從而使其和 S 相同,我們將這個單詞定義為可擴張的(stretchy)楼咳。擴張操作定義如下:選擇一個字母組(包含字母 c )熄捍,然后往其中添加相同的字母 c 使其長度達到 3 或以上。例如爬橡,以 "hello" 為例治唤,我們可以對字母組 "o" 擴張得到 "hellooo",但是無法以同樣的方法得到 "helloo" 因為字母組 "oo" 長度小于 3糙申。此外宾添,我們可以進行另一種擴張 "ll" -> "lllll" 以獲得 "helllllooo"。如果 S = "helllllooo"柜裸,那么查詢詞 "hello" 是可擴張的缕陕,因為可以對它執(zhí)行這兩種擴張操作使得 query = "hello" -> "hellooo" -> "helllllooo" = S。輸入一組查詢單詞疙挺,輸出其中可擴張的單詞數(shù)量扛邑。

示例:
輸入:
S = "heeellooo"
words = ["hello", "hi", "helo"]
輸出:1
解釋:
我們能通過擴張 "hello" 的 "e" 和 "o" 來得到 "heeellooo"。
我們不能通過擴張 "helo" 來得到 "heeellooo" 因為 "ll" 的長度小于 3 铐然。
提示:
0 <= len(S) <= 100蔬崩。
0 <= len(words) <= 100。
0 <= len(words[i]) <= 100搀暑。
S 和所有在 words 中的單詞都只由小寫字母組成沥阳。

思路:這個題怎么說呢,因為S和words的長度都才100.所以其實我覺得暴力法應該可能也許大概就不會超時自点。一個個單詞來看就行桐罕。當然了也可以先進行一場遍歷。就是看字母合不合適桂敛。比如測試案例中的hi功炮。這個i都在s中不存在,所以肯定不行术唬。薪伏。題目感覺不是很難,具體怎么實現(xiàn)我去寫代碼試試碴开。
...怎么說呢毅该,這個屌代碼博秫,我一邊寫一遍覺得有問題潦牛,但是寫完了居然ac了眶掌。而且性能還很不錯。巴碗。朴爬。所以說直覺果然不靠譜,直接貼代碼:

class Solution {
    int n;
    public int expressiveWords(String S, String[] words) {
        if("".equals(S)) return 0;
        int ans = 0;
        int[] temp = new int[100];
        char[] c = new char[100];
        int count = 1;        
        int idx = 0;
        char[] arr = S.toCharArray();
        char cur = arr[0];
        for(int i = 1;i<arr.length;i++) {
            if(arr[i] == arr[i-1]) {
                count++;
            }else {
                temp[idx] = count;
                c[idx] = cur;
                idx++;
                count = 1;
                cur = arr[i];
            }
        }
        temp[idx] = count;
        c[idx] = cur;
        n = idx;
        for(String s:words) {
            if(isOk(s, temp,c)) ans++;
        }
        return ans;
    }
    public boolean isOk(String s,int[] temp,char[] c) {
        int count = 1;        
        char[] arr = s.toCharArray();
        char cur = arr[0];
        int idx = 0;
        for(int i = 1;i<arr.length;i++) {
            if(arr[i] == arr[i-1]) {
                count++;
            }else {
                //三種false:1.字母都不一樣橡淆。2.S的個數(shù)少于s的(只能擴不能縮)召噩。3.S中個數(shù)小于3個,但是數(shù)目不同
                if(cur != c[idx] || temp[idx]<count ||(temp[idx]<3&&temp[idx] != count)) return false;
                idx++;
                count = 1;
                cur = arr[i];
            }
        }
        if(cur != c[idx] || temp[idx]<count ||(temp[idx]<3&&temp[idx] != count)|| idx != n) return false;
        return true;
    }
}

不知道是不是我個人問題逸爵,代碼寫的賊墨跡具滴。。大概思路就是首先把S作為一個模板师倔。其中每一個出現(xiàn)的元素和元素的個數(shù)都記錄出來构韵。我這里是用了兩個數(shù)組。關于這里兩個數(shù)組我想了好多趋艘。一開始是打算用二維數(shù)組疲恢,后來發(fā)現(xiàn)不知道長度比較不容易實現(xiàn)。后來我又打算用List型Map瓷胧,單純的Map沒有順序显拳,肯定不行。但是我又覺得List底層還是數(shù)組搓萧,所以最終如上方式實現(xiàn)的杂数。
記錄好模板的每一個元素出現(xiàn)順序和個數(shù)。接下來用所有的可選項去一一比較瘸洛。
這里需要注意的就是不滿足的條件:

  1. 字符不一樣直接false揍移。
  2. 字符一樣的前提下。子串比S的數(shù)目都多了货矮,直接false羊精。因為只能擴不能縮
  3. 字符一樣,也是S的多囚玫,但是S的都不滿3個喧锦。所以不能進行擴,兩個不相等就false抓督。

最主要的是最后一個字符的判斷燃少,要看兩者出現(xiàn)的字符個數(shù)是不是相等的。比如S是hheeel铃在,子串hhe阵具“椋看似上面三點都滿足了,但是實際上S中最后一個l丟了阳液,一看也是不合格怕敬。
以上的判斷都過了就是合格的,結(jié)果+1.
然后寫法上我去看看性能第一的代碼吧
我就簡單看了下帘皿,也一大串一點沒看出簡單东跪,所以就不復制了。這個題可能思路也就這樣了鹰溜。
本篇筆記就記到這里虽填,如果稍微幫到你了記得點個喜歡點個關注,也祝大家工作順順利利曹动!

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末斋日,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子墓陈,更是在濱河造成了極大的恐慌恶守,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,331評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件跛蛋,死亡現(xiàn)場離奇詭異熬的,居然都是意外死亡,警方通過查閱死者的電腦和手機赊级,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,372評論 3 398
  • 文/潘曉璐 我一進店門押框,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人理逊,你說我怎么就攤上這事橡伞。” “怎么了晋被?”我有些...
    開封第一講書人閱讀 167,755評論 0 360
  • 文/不壞的土叔 我叫張陵兑徘,是天一觀的道長。 經(jīng)常有香客問我羡洛,道長挂脑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,528評論 1 296
  • 正文 為了忘掉前任欲侮,我火速辦了婚禮崭闲,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘威蕉。我一直安慰自己刁俭,他們只是感情好,可當我...
    茶點故事閱讀 68,526評論 6 397
  • 文/花漫 我一把揭開白布韧涨。 她就那樣靜靜地躺著牍戚,像睡著了一般侮繁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上如孝,一...
    開封第一講書人閱讀 52,166評論 1 308
  • 那天宪哩,我揣著相機與錄音,去河邊找鬼暑竟。 笑死斋射,一個胖子當著我的面吹牛育勺,可吹牛的內(nèi)容都是我干的但荤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,768評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼涧至,長吁一口氣:“原來是場噩夢啊……” “哼腹躁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起南蓬,我...
    開封第一講書人閱讀 39,664評論 0 276
  • 序言:老撾萬榮一對情侶失蹤纺非,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后赘方,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體烧颖,經(jīng)...
    沈念sama閱讀 46,205評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,290評論 3 340
  • 正文 我和宋清朗相戀三年窄陡,在試婚紗的時候發(fā)現(xiàn)自己被綠了炕淮。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,435評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡跳夭,死狀恐怖涂圆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情币叹,我是刑警寧澤润歉,帶...
    沈念sama閱讀 36,126評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站颈抚,受9級特大地震影響踩衩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜贩汉,卻給世界環(huán)境...
    茶點故事閱讀 41,804評論 3 333
  • 文/蒙蒙 一驱富、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧雾鬼,春花似錦萌朱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,276評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽酒贬。三九已至,卻和暖如春翠霍,著一層夾襖步出監(jiān)牢的瞬間锭吨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工寒匙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留零如,地道東北人。 一個月前我還...
    沈念sama閱讀 48,818評論 3 376
  • 正文 我出身青樓锄弱,卻偏偏與公主長得像考蕾,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子会宪,可洞房花燭夜當晚...
    茶點故事閱讀 45,442評論 2 359

推薦閱讀更多精彩內(nèi)容