swift算法:格雷编码

1、描述

格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异。

给定一个代表编码总位数的非负整数n,打印其格雷编码序列,格雷编码序列必须以0开头。

例1:

       输入:2

       输出:[0, 1, 3, 2]

       解释:对于给定的n,其格雷编码序列并不唯一,[0, 2, 3, 1]也是一个有效的格雷编码序列

                  00 - 0

                   01 - 1

                   11 - 3

                   10 - 2

例2:

       输入:0

       输出:[0]

       解释:我们定义格雷编码序列必须以0开头,给定的编码总位数为n的格雷编码序列,其长度为 2^n。当 n = 0 时,长度为2^0 = 1。因此,当n=0时,其格雷编码序列为[0]。

 

2、算法

解法一:镜射排列/动态规划

思想:大问题转化成小问题求解

 如果知道了 n = 2 的解的话,如果是 { 0, 1, 3, 2},那么 n = 3 的解就是 { 0, 1, 3, 2, 2 + 4, 3 + 4, 1 + 4, 0 + 4 },即 { 0 1 3 2 6 7 5 4 }。之前的解直接照搬过来,然后倒序把每个数加上 1 << ( n - 1) 添加到结果中即可。

时间复杂度::O(2^n)

func grayCode(_ n: Int) -> [Int] {
        /*
         动态规划/镜射排列
         */
        var gray : [Int] = [Int]()
        //初始化n=0的解
        gray.append(0)
        for i in 0..<n{
            //要加的数
            let add : Int = 1 << i
            //倒序遍历,并且加上一个值添加到结果中
            var j = gray.count-1
            while j >= 0{
                gray.append(gray[j]+add)
                j -= 1
            }
        }
        return gray
    }
    

解法二:直接排列/直接推导

思想:        
         生成格雷码的思路:以二进制为 0 值的格雷码为第零项,第一项改变最右边的位元,第二项改变右起第一个为1的位元的左边位元,第三、四项方法同第一、二项,如此反复,即可排列出n个位元的格雷码。


         以 n = 3 为例。
         0 0 0 第零项初始化为 0。
         0 0 1 第一项改变上一项最右边的位元
         0 1 1 第二项改变上一项右起第一个为 1 的位元的左边位
         0 1 0 第三项同第一项,改变上一项最右边的位元
         1 1 0 第四项同第二项,改变最上一项右起第一个为 1 的位元的左边位
         1 1 1 第五项同第一项,改变上一项最右边的位元
         1 0 1 第六项同第二项,改变最上一项右起第一个为 1 的位元的左边位
         1 0 0 第七项同第一项,改变上一项最右边的位元

时间复杂度: 由于每添加两个数需要找第一个为 1 的位元,需要 O(n),O(n2^n)

func grayCode(_ n: Int) -> [Int] {
        /*
         直接推导(直接排列)
         */
        var gray : [Int] = [Int]()
        //初始化n=0的解
        gray.append(0)
        var i = 1
        while i < 1 << n{
            //得到上一个的值
            var previous = gray[i-1]
            //同一项的情况
            if i%2 == 1 {
                //和0000001 做异或,使得最右边一位取反
                previous = previous ^ 1
                gray.append(previous)
            //同第二项的情况
            }else{
                var temp = previous
                //寻找右边起第一个为1的位元
                for j in 0..<n {
                    if temp&1 == 1 {
                        //和 00001000000 类似这样的数做异或,使得相应位取反
                        previous = previous^(1<<(j+1))
                        gray.append(previous)
                        break
                    }
                    temp = temp>>1
                }
            }
            i += 1
        }
        return gray
    }
    

解法三:公式/二进制转格雷编码

思想:二进制转格雷码 G(n)=B(n+1) XOR B(n)
         利用公式转换即可。即最高位保留,其它位是当前位和它的高一位进行异或操作。

时间复杂度:O(2^n)

func grayCode(_ n: Int) -> [Int] {
        /*
         公式/二进制转格雷码
         */
        var gray : [Int] = [Int]()
        var binary = 0
        while binary < 1 << n {
            gray.append(binary ^ (binary>>1))
            binary += 1
        }
        return gray
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值