• [leetcode 周赛 160] 1238 循环码排列


    1238 Circular Permutation in Binary Representation 循环码排列

    问题描述

    给你两个整数 nstart。你的任务是返回任意 (0,1,2,,...,2^n-1) 的排列 p,并且满足:

    • p[0] = start
    • p[i]p[i+1] 的二进制表示形式只有一位不同
    • p[0]p[2^n -1] 的二进制表示形式也只有一位不同

    示例 1:

    输入: n = 2, start = 3
    输出: [3,2,0,1]
    解释: 这个排列的二进制表示是 (11,10,00,01)
    所有的相邻元素都有一位是不同的,另一个有效的排列是 [3,1,0,2]

    示例 2:

    输出: n = 3, start = 2
    输出: [2,6,7,5,4,0,1,3]
    解释: 这个排列的二进制表示是 (010,110,111,101,100,000,001,011)

    提示:

    • 1 <= n <= 16
    • 0 <= start < 2^n

    思路

    • 读题
      所求序列是一个格雷码序列, 相邻的二进制只有一位不同(有效位数), 首尾同样只有一位不同
      题目虽然给出了开始位置, 但其实就是一个循环, 找到一个循环序列即可

    DFS图遍历

    二进制, 从全0到全1, 每次改变一位, 生成一份边上两节点为只相差一位的图
    从给定起始点出发, 选择一条边到下一节点, 不重复经过节点, 最终节点为自己
    同以上方式, 筛选出一条循环的线路
    DFS图遍历

    格雷码生成

    格雷码生成公式: [i] = i^(i>>>1) 自己与自己左移一位相异或

    • 举例: 3位
    i i i>>>1 [i] [i]
    0 000 000 000 0
    1 001 000 001 1
    2 010 001 011 3
    3 011 001 010 2
    4 100 010 110 6
    5 101 010 111 7
    6 110 011 101 5
    7 111 011 100 4

    格雷码生成

    代码实现

    DFS图遍历

    class Solution {
        public List<Integer> circularPermutation(int n, int start) {
            // 该序列节点数
            int len = 1 << n;
            // 在图遍历中 存储已经过的节点
            Set<Integer> visited = new HashSet<>(len);
            // 符合条件的答案 序列
            List<Integer> ans = new ArrayList<>(len);
    
            // 首先置入起点
            visited.add(start);
            ans.add(start);
            // 图遍历DFS开始
            dfs(n, start, ans, visited);
    
            return ans;
        }
    
        private boolean dfs(int n, int prev, List<Integer> ans, Set<Integer> visited) {
            // 判断是否进行到最后一个节点的判断
            if (ans.size() == (1 << n)) {
                // 判断首尾节点是否符合条件
                int first = ans.get(0), end = ans.get(ans.size() - 1);
                // 判断两数字是否只有一位不同: ((a^b)&((a^b)-1)) == 0
                // 解释: 如果两个数字只有一位不同, 那么相异或时相同位置为0 不同为置为1 即只有一位为1其余全为0
                int temp = first ^ end;
                // 如果First End只有一位不同 (101^001 --> 001 --> 001&000 == 0
                return (temp & (temp - 1)) == 0;
            }
    
            for (int i = 0; i < n; i++) {
                // 下一个符合条件的节点
                int next = prev ^ (1 << i);
                // 如果不曾访问过
                if (!visited.contains(next)) {
                    visited.add(next);
                    ans.add(next);
                    // 寻找下一符合条件的节点
                    if (dfs(n, next, ans, visited)) {
                        return true;
                    }
                    ans.remove(ans.size() - 1);
                    visited.remove(next);
                }
            }
    
            return false;
        }
    }
    

    格雷码生成

    class Solution {
        public List<Integer> circularPermutation(int n, int start) {
            int size = 1 << n;
            int[] arr = new int[size];
            // 生成格雷码
            for (int i = 0; i < size; i++) {
                arr[i] = i ^ (i>>>1);
            }
    
            List<Integer> ans = new ArrayList<>();
            for (int i = 0; i < size; i++) {
                // 从指定起始点开始
                if (arr[i] == start) {
                    for (int j = 0; j < size; j++) {
                        int next = (i+j) % size;
                        ans.add(arr[next]);
                    }
                    return ans;
                }
            }
    
            return ans;
        }
    }
    

    参考资源

    第 160 场周赛 全球排名

  • 相关阅读:
    python自动化测试(3)- 自动化框架及工具
    python自动化测试(2)-自动化基本技术原理
    软件开发过程自动化原理及技术(完整示例)
    网络验证码--你到底是爱它还是恨它?
    python的高性能web应用的开发与测试实验
    接口应用小玩具-博客园积分排名变动监控工具
    openwrt-智能路由器hack技术(2)---"网路信息监控和窃取"
    Java中的Date和时区转换
    fastjson JSONObject遍历
    【git】强制覆盖本地代码(与git远程仓库保持一致)
  • 原文地址:https://www.cnblogs.com/slowbirdoflsh/p/11823498.html
Copyright © 2020-2023  润新知