n对括号的所有的合法组合排序解法

题目很简单,给定数字n,写出所有n组括号的分布情况

例如n=2,则有(()),()(),这两种

n=3,则有

((())),(()()),(())(),()(()),()()() 五种。

看到这个问题,第一反应可能是用递归,要得到 f(n), 等价于再f(n-1)的基础上加一对括号,

只要保证左右括号的相对位置即可!

例如:F(2), 等于再"()"上加一对括号;可能有以下几种情况:

()),()()(),()()),

其中红色是原来的位置,黑色是插入的位置。

显然会出现大量重复组合,所以用这种办法,可能需要借助HashSet来去重。

那有没有更简单的办法呢?


我们将左括号记为 1,右括号记为0,那么n对括号就等价于  n个“1”和n个“0”的组合,构成一个二进制数,且第一位一定是1(左括号),最后一位一定是0(右括号)

所以表现形式位 1xxxxxxxxx0,且每一位的左边1的个数不小于0的个数,每一位的右边,0的个数不小于1的个数。

所以我们有如下算法:

 public static void p8_9(List<int> nums,int left,int right,int remain,int index,int pre)
        {
            if (remain == 0)
            {
                nums.Add(pre);
                return;
            }
          
            if(left>right)
            {
                //补零不变
                p8_9(nums, left, right + 1, remain, index - 1, pre);
            }
            //补1总是没问题,补1则remain减少
            pre = pre | (1 << index);
            index--;
            left++;
            remain--;
            p8_9(nums, left, right, remain, index, pre);
        }

        public static void TestP8_9(int n)
        {
            int num = 1 << (n * 2-1);
            List<int> nums = new List<int>();
            p8_9(nums, 1, 0, n - 1, 2 * n - 2, num);

            nums.ForEach(x => Console.WriteLine(Convert.ToString(x, 2)));


        }

思路如下:

首先参数:

1 nums:存放最终的排列结果

2.left:统计当前index左边1的个数

3.right:统计当前index左边0的个数

4.index:游标,从左边第二位开始

5.pre:临时存放的数字, 初始为 1<<(2n-1);

6.remain: 剩余需要将0变为1的次数

假设n=3; 构建一个1<<(2*3-1) =100000;

此时参数为 left=1,right=0,remian=2,index=5,pre=100000

a.如果 ramain==0;即已经有三个1了,那么构造结束,将结果加入nums

b.如果左边1的个数大于0的个数比如 110000,那么index=3时,可以设为0,不出出现right>left的情况 ;如果时100000,那么就不能出现100xxx这种结构了,因为后面无论怎么排列都无法使之合法。所以设为0后,right的数目加1,remain保持不变,index往后移(index--).然后继续迭代

c.无论什么情况,只要剩余变1的次数不为0,就可以一直将该位设为1,极端情况就是111000,

这种情况要记得更新remain,他是终止运行的条件。

下面时n=4的运行结果:

10101010
10101100
10110010
10110100
10111000
11001010
11001100
11010010
11010100
11011000
11100010
11100100
11101000
11110000

将1->( ,0->),即可得到最终结果。

当然有个问题是,如果n太大超过16怎么办(即超过int32位数),这里可以用字符串实现,完全没问题。其次参数时可以简化的,知道index和left,right可以计算出来,remain也可以计算出来,这里为了直观,就没有简化。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值