646. Maximum Length of Pair Chain

646. Maximum Length of Pair Chain
找到符合规则的最长chain。
weekly contest 42的第二题。
我一看感觉很简单,就是dfs,但是总也写不出,各种Wrong Answer
最后想了一下,这个就是类似Permutation的「排列」问题。晚上整理了一下,写了下面的代码,总算不Wrong Answer了,但是TLE了,不过思路是比较清晰的:

我的DFS解法(TLE):

//注意,以下代码会TLE:
    int max = 1;

    public int findLongestChain(int[][] pairs) {
        if (pairs == null || pairs.length == 0) return 0;
        chainDfs(pairs, new boolean[pairs.length], 0, Integer.MIN_VALUE);
        return max;
    }

    private void chainDfs(int[][] pairs, boolean[] used, int count, int b) {
//不需要terminator
        for (int i = 0; i < pairs.length; i++) {
            if (!used[i] && pairs[i][0] > b) {
                used[i] = true;
                max = Math.max(count + 1, max);
                chainDfs(pairs, used, count + 1, pairs[i][1]);
                used[i] = false;
            }
        }
    }

既然TLE了,就说明有可以优化的地方。
这题有个条件是In every pair, the first number is always smaller than the second number. 这说明,如果我们以第一个数字排序,那后一个数组[a,b]的第二个数字(b)是一定大于前一个数组[c,d]的的第一个数字(c)的。这样可以减少很多次递归。

优化了一下:


    int max = 1;

    public int findLongestChain(int[][] pairs) {
        if (pairs == null || pairs.length == 0) return 0;
//      Arrays.sort(pairs, (a, b) -> a[1] - b[1]);
        Arrays.sort(pairs, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[0] - o2[0];
            }
        });
        chainDfs(0, pairs, new boolean[pairs.length], 0, Integer.MIN_VALUE);
        return max;
    }

    private void chainDfs(int index, int[][] pairs, boolean[] used, int count, int b) {
        if (index == pairs.length)
            return;
        for (int i = index; i < pairs.length; i++) {
            if (!used[i] && pairs[i][0] > b) {
                used[i] = true;
                max = Math.max(count + 1, max);
                chainDfs(i + 1, pairs, used, count + 1, pairs[i][1]);
                used[i] = false;
            }
        }
    }

可是万万没想到,仍然TLE...test case确实非常大,用DFS的话栈深度不可想象。

看了下大家的discussion,有两种算法,一种是Greedy,说是跟CLRS上的activity selection几乎一模一样(还有interval 问题)。。顿时觉得自己基础差。

另一种是DP。今天先到这儿了。

--

26 July Update

GREEDY(ITERATION)

复习了一下activity selection问题,发现这题跟那个几乎是一致的。写了一下代码,但是我其实并不能说服自己greedy得到的答案就是正确的,这一点跟dp不太一样,dp是有理有据的,而greedy仿佛是需要证明的,据说greedy经常用剪枝来证明,fine,又一个我认识他他不认识我的名词。。今天先到这,这题还没完。

    public int findLongestChain(int[][] pairs) {
        if (pairs == null || pairs.length == 0) return 0;
        int count = 1;
        Arrays.sort(pairs, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[1] - o2[1];
            }
        });

        int index = 0;
        for (int i = 1; i < pairs.length; i++) {
            if (pairs[i][0] > pairs[index][1]) {
                count++;
                index = i;
            }
        }
        return count;
    }

27 July Update

GREEDY(RECURSION)

看了算法导论上的活动选择问题,这题还可以用递归来做,或者说,所有的for循环都能改成递归?
这题的递归实现:

    public int findLongestChain(int[][] pairs) {
        if (pairs == null || pairs.length == 0) return 0;
        Arrays.sort(pairs, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[1] - o2[1];
            }
        });
        recursion(pairs, 0);
        return cnt;
    }

    int cnt = 1;

    private void recursion(int[][] pairs, int index) {
        int m = index + 1;
        while (m < pairs.length && pairs[index][1] >= pairs[m][0]) {
            m++;
        }
        if (m < pairs.length) {
            cnt++;
            recursion(pairs, m);
        }
    }

DP

看了另外有人用DP做的,但是这题用DP有点浪费了,它这个方法跟Weighted Job Scheduling Dynamic Programming的思路是一致的,工作安排比这个多一个要考虑的地方,就是不同的工作既要不冲突,而且因为每份工作的报酬不一样,不能简单地只考虑完成时间最短,所以只能用DP。那这题跟Job Schedule唯一的不同就是在if判断的地方,这题是dp[i] < dp[j] + 1,如果是Job Schedule就要是dp[i] < dp[j] + profit[i]。
两重循环的解法让人想起LIS PROBLEM(JOB SCHEDULE跟LIS的判断方法一模一样)。

public class Solution {
    public int findLongestChain(int[][] pairs) {
        Arrays.sort(pairs, (a, b) -> (a[0] - b[0]));
        
        int i, j, max = 0, n = pairs.length;
        int dp[] = new int[n];
      
        for (i = 0; i < n; i++) dp[i] = 1;
        
        for (i = 1; i < n; i++)
            for (j = 0; j < i; j++)
                if (pairs[i][0] > pairs[j][1] && dp[i] < dp[j] + 1)
                    dp[i] = dp[j] + 1;

        for (i = 0; i < n; i++) if (max < dp[i]) max = dp[i];
        
        return max;
    }
}

疑问:用DP为什么要sort,为什么按照开始时间和结束时间sort都能AC,不sort就无法AC?

另外,这题的GREEDY,我还是不太懂得如何证明,算法导论上有证明,我没细看。据说通常用剪枝证明GREEDY。

ref:
http://www.cnblogs.com/hapjin/p/5573419.html
http://www.jianshu.com/p/293a4056a50a

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容