zoukankan      html  css  js  c++  java
  • LeetCode1238循环码排列

    题目

    给你两个整数 n 和 start。你的任务是返回任意 (0,1,2,,...,2n-1) 的排列 p,并且满足:
    p[0] = start
    p[i] 和 p[i+1] 的二进制表示形式只有一位不同
    p[0] 和 p[2n -1] 的二进制表示形式也只有一位不同

    思路

    暴力回溯:O(n*2n)

    f(s,visited,listRes)用s标识二进制的字符串
    if(visited.size())==162)则可以直接返回。
    加入s到结果和visited中。
    找到s的邻居neib,并且neib步骤visited中:递归访问f(neib,visited,listRes)
    回退:从visited和listRes中删除元素。

    由于要在队尾队头操作,所以用LinkedList。
    最后把得到的listRes的字符串转成十进制数字。

     public List<Integer> circularPermutation(int n, int start) {
        List<Integer> res=new ArrayList<>();
        String biStart=Integer.toBinaryString(start);
        StringBuilder stringBuilder=new StringBuilder(n);
        int diffLen=n-biStart.length();
        for (int i = 0; i < diffLen; i++) {
            stringBuilder.append("0");
        }
        stringBuilder.append(biStart);
        LinkedList<StringBuilder> tmpRes=new LinkedList<>();
        int totalSize= (int) (Math.pow(2,n));
        helper(tmpRes,stringBuilder,new HashSet<String>(),totalSize);
        //把字符串转成int
        for (StringBuilder stringBuilder1:tmpRes){
            res.add(Integer.parseInt(stringBuilder1.toString(),2));
        }
        return res;
    }
    
    /**
     *
     * @param list
     * @param stringBuilder
     * @param visited
     * @param totalSize
     * @return 是否能成功
     */
    private boolean helper(LinkedList<StringBuilder> list, StringBuilder stringBuilder, HashSet<String> visited, int totalSize) {
    String str=stringBuilder.toString();
        visited.add(str);
        list.addLast(stringBuilder);
        if(visited.size()==totalSize){
            return true;
        }
    
    
        for (int i = 0; i < stringBuilder.length(); i++) {
            //如果没有visite过,则
            StringBuilder neib=new StringBuilder(stringBuilder);
            char ch=stringBuilder.charAt(i);
            neib.setCharAt(i,ch=='0'?'1':'0');
            if(!visited.contains(neib.toString())){
                if(helper(list,neib,visited,totalSize)){
                    return true;
                }
            }
        }
        visited.remove(str);
        list.removeLast();
    
        return false;
    }
    

    格雷码O(2N)

    先生成所有格雷码,再找到开头

    在一组数的编码中,若任意两个相邻的代码只有一位二进制数不同,则称这种编码为格雷码(Gray Code),
    另外由于最大数与最小数之间也仅一位数不同,即“首尾相连”,因此又称循环码或反射码。

    生成格雷码的方法:
    先生成0~4个元素的格雷码:00,01,11,10
    那么4~8的格雷码的生成方法是:在所有元素前面加上1
    100,101,111,110,为了能和前四个元素接上,可以把后面这些新元素逆置,换句话说,生成元素的时候选择从后向前变量。

    重点在于这种头尾相连的方式。
    如果用字符串实现前置1,则需要补0,所以用数字实现更好。

     List<Integer> res=new ArrayList<>();
        //
        int totalSize= (int) (Math.pow(2,n));
        int size=2;
        res.add(0);
        res.add(1);
        int added=2;
        while(size<totalSize){
            int lastSize=res.size();
            for(int i=lastSize-1;i>=0;i--){
                res.add(added+res.get(i));//需要补0,直接用数字表示更好
            }
            added<<=1;
            size+=lastSize;
        }
        //
        List<Integer> trueRes=res;
        System.out.println(trueRes);
        int startPoint=trueRes.indexOf(start);
        List<Integer> rt=new ArrayList(trueRes.subList(startPoint,totalSize));
        rt.addAll(trueRes.subList(0,startPoint));
        return rt;
    }
    
  • 相关阅读:
    LeetCode449. 序列化和反序列化二叉搜索树
    LeetCode448. 找到所有数组中消失的数字
    一行代码如何隐藏 Linux 进程?
    C语言这么厉害,它自身又是用什么语言写的?
    了解C语言,是否代表了解C ++的一半?
    C语言小白那些不知道的事儿
    6 条 Git 实用技巧
    干货来袭,收藏方便找到该网站
    零基础小白如何入门Shell,快来看看(收藏)这篇大总结!!
    Java用于嵌入式系统的优点和局限
  • 原文地址:https://www.cnblogs.com/FannyChung/p/leetcode1238.html
Copyright © 2011-2022 走看看