Generate Parentheses 【Leetcode】

来源:互联网 发布:简洁html网址导航源码 编辑:程序博客网 时间:2024/04/29 15:49

哥们存在的意义就是为了衬托神的存在,又一次体现了渣代码和神代码的区别


又是无聊记忆搜索dp,懒得写优化的key直接拿中间结果存key了。

其实我觉得这个题的关键在于如何抽象这个结果的表示形式,我只想到了用一个二维数组进行存储,

2,1

2,1 


表示第一位置上两个左括号两个右括号,第二个位置上一个左一个右。[[]][]

还有一种特殊情况,就是

2,1

1,2

对应于[[][]]  注意dp内循环的顺序,右括号永远在左括号右边,防止出现

1,2

2,1

对应[]][[],显然这是个错误解


int[][] ms = new int[2][];ArrayList<String> res = new ArrayList<String>();HashMap<String, Integer> traceMap = new HashMap<String, Integer>();public String getLR(int num, int lr) {String s = "";String basic = "(";if (lr == 1)basic = ")";for (int i = 0; i < num; i++)s += basic;return s;}public String getRes(boolean save) {//String ds="";//for (int i = 0; i < ms[0].length; i++) {//if(ms[0][i]==0)//continue;//ds+=ms[0][i]+"/"+ms[1][i]+", ";//}//System.out.println(ds);String s = "";for (int i = 0; i < ms[0].length; i++) {if(ms[0][i]==0)continue;s += getLR(ms[0][i], 0) + getLR(ms[1][i], 1);}if (save)res.add(s);return s;}public void dp(int n, int currentMax) {//System.out.println("dp  n="+n+"  currentMax="+currentMax);String key = getRes(false);Integer v = traceMap.get(key);if (v != null)return;traceMap.put(key, 1);if (n <= 0){getRes(true);return;}for (int i = 0; i <currentMax; i++) {ms[0][i]++;for (int j = i; j <currentMax; j++) {ms[1][j]++;dp(n - 1, currentMax);ms[1][j]--;}ms[0][i]--;}ms[0][currentMax] = 1;ms[1][currentMax] = 1;dp(n - 1, currentMax + 1);ms[0][currentMax] = 0;ms[1][currentMax] = 0;}public ArrayList<String> generateParenthesis(int n) {ms[0] = new int[n + 1];ms[1] = new int[n + 1];dp(n, 0);return res;}

========================================

再看看人家的神代码

ArrayList<String> res=new ArrayList<String>();int n;public void dp(String s, int l,int r){if(l==n){//for(int i=0;i<l-r;i++)//s+=")";res.add(s);return;}dp(s+"(",l+1,r);if(l>r)dp(s+")",l,r+1);}public ArrayList<String> generateParenthesis(int N) {n=N;dp("",0,0);return res;}

中间两句我注释掉了,不注释掉就是最终结果。这个思路太秒了。其实还是dp,但是人家分析获得的状态专一方程是和渣不一样的。去掉注释运行一下看看结果就能想明白为什么这么做了。对于N,一定有N个左括号和N个有括号(废话)。


1.既然一定有n个左括号,我们就先把n个左括号画出来,一个左括号占一个数组位置,剩下的问题就是考虑每个数组单元里放几个右括号的问题了。(假设数组存在为a[]=new a[n]);

2.问题是随意排列,有错误解,因此需要定义错误解。从左往右读,遇到l则+1,遇到r则-1,sum<0则是错误解,从右往左亦然。所以半神解法就是来个全排列然后根据错误解定义删掉错误解。

注意:这个解法需要数组a[],这个方法如果求n个括号的解的个数的时候会很快,但在这个题里搞不过神DP啊


3. 最后在来看神的DP解,其实他用的就是最普通的状态转移方程,每添加一个字符就进入新的状态。正确性判断就是任何状态从左向右l>=r即可,注意L的控制由n完成。


个人感受:

感觉做DP就是多做多做突然就顿悟了,虽然人家都说边界条件,状态控制很多很多,但你自己没有真正遇到过就没有什么感受。

还有DP的关键就是分析,这个题解法很多,从我最笨的二维数组定义状态到神的单字符状态,重要的是结合题意,

1. 分析清楚,变化的是什么,是一个字符,一个单词,还是什么。找好变化量,往往能使半功倍

2. 搞清楚状态控制条件,如果变化量选的不合适,状态控制条件就会非常复杂

3. 记忆优化,渣都知道的东西就不提了

4. 没事了总想试试bottom up 从来没成过,这个题貌似也高不了吧


Reright @ 2014-1-31

 ArrayList<String> reslist=new ArrayList<String>();    int[] res;    int num;    public void genRes(){//    for(int i:res)//    System.out.print(i+" ");//    System.out.println();        String s="";        for(int i=1;i<res.length;i++){            s+="(";            for(int j=0;j<res[i];j++)                s+=")";        }        reslist.add(s);    }    public void dp(int position,int usedright){    //System.out.println("dp  "+position+"  "+usedright);        if(usedright>=position)            return;        if(position==num){            res[num]=num-usedright;            genRes();            return;        }        for(int i=0;i<=position;i++){            res[position]=i;            dp(position+1,usedright+i);        }    }    public ArrayList<String> generateParenthesis(int n) {        res=new int[n+1];        if(n==0)            return reslist;        num=n;        dp(1,0);        return reslist;    }



Code Rewrite:



 ArrayList<String> reslist = new ArrayList<String>();int num;public void dp(int p, int leftp, String s) {if (p == num){for(int i=1;i<=leftp;i++)s+=")";reslist.add(s);return;}String ts = "";for (int i = 0; i <= leftp; i++) {dp(p + 1, leftp + 1 - i, s + ts+ "(" );ts += ")";}}public ArrayList<String> generateParenthesis(int n) {num = n;dp(0, 0, "");return reslist;}




0 0
原创粉丝点击