Leetcode Weekly Contest 107

压哨做完4道。
总结下思路吧。

925. Long Pressed Name

https://leetcode.com/problems/long-pressed-name/description/
这道题很快就秒了。一开始字符一定要一样。随后如果出现不一样,我们就看是不是长按造成的,一直去掉重复字符。重复字符都去完了,应该一样了,如果还不一样就FALSE。

public boolean isLongPressedName(String name, String typed) {
        if(name.equals(typed)) return true;
        char[] ns = name.toCharArray();
        char[] ts = typed.toCharArray();
        int j = 0;
        for(int i = 0; i < ns.length; ) {
            if(j == ts.length) return false;
            if(ns[i] != ts[j]) return false;
            else{
                j++;
                i++;
                if(i == ns.length){
                    while(j < ts.length && ts[j] == ts[j-1]) j++;
                    return j == ts.length;
                }
                while(j < ts.length && ts[j] != ns[i] && ts[j] == ts[j-1]) j++;
            }
            
        }
        return true;
    }

926. Flip String to Monotone Increasing

https://leetcode.com/problems/flip-string-to-monotone-increasing/description/
这道题是一维数组加状态机的动态规划。

我们假定DP J,是到J位符合递增的序列. 那么根据J位是0或1,我们会有2个状态。
如果J位是0,我们只能从J-1位是0得过来。同时如果这个是字符串的第J个和最后的状态要求不同,需要翻成对应字符而需要+1。

如果J位是1,我们可以从J-1位是0 或者J-1位是1得过来。同时如果这个是字符串的第J个和最后的状态要求不同,需要翻成对应字符而需要+1。

public int minFlipsMonoIncr(String S) {
        char[] A = S.toCharArray();
        int n = A.length;
        int[] one = new int[n + 1];
        int[] zero = new int[n + 1];

        zero[0] = one[0] = 0;
        
        int i;
        for (i = 1; i <= n; i++) {
            one[i] = A[i - 1] == '1' ? Math.min(one[i - 1], zero[i - 1]) : 
                                      Math.min(one[i - 1], zero[i - 1]) + 1;
            zero[i] = A[i - 1] == '0' ? zero[i - 1] : zero[i - 1] + 1;
        }
        return Math.min(zero[n], one[n]);
    }

927. Three Equal Parts

这道题思考过程是这样,看了数据规模得出 解的时间复杂度应该是ON,那么暴力解法肯定不行。
O N + 分成3段,就想到2个指针。那么2个指针就很容易想到双向指针。
那么我就把第一个指针放在头部,后一个指针放在尾部,开始找能不能指针只会往中间走而不回退的方法。
我发现,如果一开始头尾指针构成的二进制数,如果是一样的。那么只要中间的部分和他们也是一样的就找到答案了。
如果不一样,分为2个情况
如果前面的 比 后面的 小
可以通过右移左指针而起到增大前面的本事。因为3个区间要相等。我们最开始已经贪心的把前后都压缩到最小,所以要补救势必是通过增大的方式。

如果后面比前面小。我们肯定要通过左移右指针去把中间的元素拿到右面,来增大右面。道理同上

如果配平了左右2面,此时一定是前缀和后缀长度最小的配平。根据贪心的思想。
我们就看这个最小的配平下,中间是不是也能配平。配平就找到解了。

如果中间的比右面的大,我们可以通过左移右指针,来试图让中间的区间减少。当然右移左指针也是可以的。为什么要选择左移右指针呢?
通过观察,右移左指针必然会使得前半部分增大。而左移右指针,可能因为是0,加了前缀0等于没加。而依然保持左半和右半配平。
如果中间的区间的值比右面的小,肯定无解了。因为我们已经为了配平左右而用了最小的长度。一旦要去从左右拿出元素,肯定就无法配平左右了。
分析到这里,思路就有了。

落实到代码,我决定用DQ,因为方便2头进出。
同时为了在做DQ compare的时候,加速。
我决定忽略所有前缀0,这增加了编码难度,但是加快了时间。
所有忽略前缀0的DQ,在比较的时候,
如果长度不同,可以直接比出大小。
如果长度相同,就依次遍历每一个值,如果全相同就同,如果一旦不同,直接比较这2个不同的值。

为了达到上述效果,我在发现每个DQ的前缀是0的情况下,就不插进去了。只有1做前缀的时候再插进去,同时需要补之前没插的0.

public int[] threeEqualParts(int[] A) {
        int i = 0, j = A.length-1;
        Deque<Integer> pre = new ArrayDeque<>();
        Deque<Integer> mid = new ArrayDeque<>();
        Deque<Integer> last = new ArrayDeque<>();
        if(A[0]!=0) pre.offerLast(1);
        if(A[j]!=0) last.offerLast(1);
        for(int k = 1; k < j; k++){
            if(mid.isEmpty() && A[k] == 0) continue;
            mid.offerLast(A[k]);
        } 
        while(i < j){
            int cp = compare(pre,last);
            if(cp<0){
                i++;
                if(A[i] == 0){
                    if(!pre.isEmpty()) pre.offerLast(0);
                } 
                else{
                    if(mid.isEmpty()) break;
                    pre.offerLast(mid.pollFirst());
                    while(!mid.isEmpty() && mid.peekFirst()==0) mid.pollFirst();
                }
            }else if(cp>0){
                j--;
                if(mid.isEmpty()) break;
                if(A[j] == 0) mid.pollLast();
                else moveMidToLast(A,mid,last,j);
            }else{
                int cp2 = compare(mid,last);
                
                if(cp2 == 0) return new int[]{i,j};
                if(cp2<0) break;
                else{
                    j--;
                    if(mid.isEmpty()) break;
                    if(A[j] == 0) mid.pollLast();
                    else moveMidToLast(A,mid,last,j);
                }
            }
        }
        return new int[]{-1,-1};
    }
    private void moveMidToLast(int[] A,Deque<Integer> mid,Deque<Integer> last,int j){
        int idx = j+1;
        while(idx<A.length && A[idx++]==0)
            last.offerFirst(0);
        last.offerFirst(mid.pollLast());
    }
    
    private int compare(Deque<Integer> a, Deque<Integer> b){
        if(a.size() < b.size()) return -1;
        if(a.size() == b.size()){
            Iterator<Integer> itr = a.iterator();
            Iterator<Integer> itr2 = b.iterator();
            while(itr.hasNext()){
                int fa = itr.next();
                int fb = itr2.next();
                if(fa == fb) continue;
                return fa-fb;
            }

            return 0;
        }
        return 1;
    }

928. Minimize Malware Spread II

最后这道题的思考过程,需要从上周比赛Minimize Malware Spread来。
区别就在于抹掉一个点,就抹掉了所有的连边。
1连2,2连3. 病毒有1,2. 直接这个局面是没救的。但是再这道题里,通过抹掉JOINT POINT 2,就能盘活局面。
但是并查集不是很好处理断开的情况。
那我就想既然如果,我索引遍历所有的病毒,依次抹掉这个病毒的情况下,重新生成一个图,然后算INFECTS的点的数量。
随后取最小值就可以了。
那么构成图的时候,其实就是在UNION,发现有一个点是抹除的病毒点,就CONTINUE就好。

int[] par;
    int[] cnt;
    int find(int i){
        if(i == par[i]) return i;
        return par[i] = find(par[i]);
    }
    boolean union(int i,int j){
        int pi = find(i);
        int pj = find(j);
        if(pi == pj) return false;
        par[pi] = pj;
        cnt[pj] += cnt[pi];
        return true;
    }
    public int minMalwareSpread(int[][] graph, int[] initial) {
        Arrays.sort(initial);
        int res = initial[0];
        int min = Integer.MAX_VALUE;
        for(int i = 0; i < initial.length; i++){
            int tmp = initial[i];
            initial[i] = -1;
            int infects = minMalwareSpread2(graph,initial,tmp);
            if(infects < min){
                min = infects;
                res = tmp;
            }
            initial[i] = tmp;
        }
        return res;
    }
    public int minMalwareSpread2(int[][] graph, int[] initial,int tar) {
        int l = graph.length;
        par = new int[l];
        cnt = new int[l];
        Arrays.fill(cnt,1);
        for(int i = 0; i < l; i++) par[i] = i;
        
        for(int i = l-2; i >= 0; i--){
            for(int j = i+1; j < l; j++){
                if(graph[i][j] == 0 || i==tar || j==tar) continue;
                union(i,j);
            }
        }
        int infects = 0;
        boolean[] seen = new boolean[l];
        for(int i : initial){
            if(i == -1) continue;
            int pi = find(i);
            if(seen[pi]) continue;
            seen[pi] = true;
            infects += cnt[pi];
        }
        
        return infects;
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,000评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,745评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,561评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,782评论 1 298
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,798评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,394评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,952评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,852评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,409评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,483评论 3 341
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,615评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,303评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,979评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,470评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,571评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,041评论 3 377
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,630评论 2 359