程序员的算法趣题:Q40 优雅的IP地址(Java版)

前提知识

IPv4:32bit(二进制形式)或 192.168.1.2(十进制形式)

题目链接(力扣网):https://leetcode-cn.com/leetbook/read/interesting-algorithm-puzzles-for-programmers/9i00p1/

题目要求

1.二进制形式:左右对称,比如11111111000000000000000011111111

2.十进制形式:0~9均出现,且不重复

求:有多少个IP符合要求

思路一

左侧共16bit,即16个二进制位,共有65536种情况。

1.遍历0~65535的每个数字,将十进制转为二进制,记为字符串a

2.将字符串a反转,记为字符串b

3.将字符串a和b每8位切一段,共四段

4.将四段二进制形式的字符串逐一转为十进制,得到十进制数A,B,C,D

5.封装方法判断字符串A+B+C+D中是否完整出现0~9且不重复,满足即为正确答案之一

代码

public static void main(String[] args) {
    List list = new ArrayList();
    for(int i = 0; i < 65536; i ++){
        String a = to2(i); // 自定义的方法to2:十进制 ==> 二进制格式
        String b = new StringBuilder(a).reverse().toString(); // 反转
        
        // 将二进制数据解析成十进制
        int A = Integer.parseInt(a.substring(0,8), 2);  // [AAAAAAAA --------]
        int B = Integer.parseInt(a.substring(8,16), 2); // [-------- BBBBBBBB]
        int C = Integer.parseInt(b.substring(0,8), 2);  // [CCCCCCCC --------]
        int D = Integer.parseInt(b.substring(8,16), 2); // [-------- DDDDDDDD]
        String target = ""+A+B+C+D;
        
        if(isUnique(target) && target.length() == 10){ // 自定义的方法isUnique
            list.add(A + "." + B + "." + C + "." + D);
        }
    }
    System.out.println(list);

}
// 十进制 => 16bit 的二进制形式
public static String to2(int num){
    StringBuilder sb = new StringBuilder();
    while(num > 0){
        sb.insert(0,""+num % 2);
        num /= 2;
    }
    while(sb.length() < 16){
        sb.insert(0, "0");
    }
    return sb.toString();
}
// 判断字符串中是否每个字符都唯一
public static boolean isUnique(String s){
    char[] cs = s.toCharArray();
    Arrays.sort(cs);
    for(int i = 0; i+1 < cs.length; i ++){
        if(cs[i] == cs[i+1]) return false;
    }
    return true;
}

思路二

从思路一可以看出:

A.B.C.D四个数字,

只要A和D的二进制对称,B和C的二进制对称即可。

然后AD在外,BC在内,有4种组合;

然后BC在外,AD在内,有4种组合。

所以只需要求出有几个可用组合,然后乘以8,就可以得到优雅IP的数量了。

代码

public static void main(String[] args) {
    // Step 1: 找出符合对称关系的A,B,C,D候选项
    List list = new ArrayList(); // 下标(0,1) (2,3) (4,5)... (偶,奇)为一对。
    for(int i = 0; i < 256; i ++){ // 只需遍历8bit的所有情况即可,所以256次循环即可
        String a = to2(i); // 8bit,形如11110000
        String b = new StringBuilder(a).reverse().toString(); // 8bit,形如00001111

        if(! list.contains(i) && ! a.equals(b)){ // 避免添加重复的元素
            list.add(i);
            list.add(Integer.parseInt(b, 2)); // 将二进制的字符串b转为十进制数据
        }
    }
    System.out.println(list);

    // Step 2: 两对两对的组合,筛选出0~9全出现的组合(两对,4个数字)
    List resList = new ArrayList<>();
    for(int i = 0; i+1 < list.size(); i += 2){ // 两个是一对,所以 i+=2
        for(int j = i+2; j+1 < list.size(); j += 2){
            int A = list.get(i);
            int B = list.get(i+1);
            int C = list.get(j);
            int D = list.get(j+1);
            String target = ""+A+B+C+D;
            if(isUnique(target) && target.length() == 10){ // 是否0~9全出现(字符串长度为10)且不重复(isUnique返回true)
                resList.add("{"+A+":"+B+","+C+":"+D+"}"); // 此处随便拼接成自己喜欢的格式,保证可读性即可
            }
        }
    }
    System.out.println("可用组合:"+resList); // 形如:[{34:68,179:205}],表示34和68是一对,179和205是一对。可以拼成34.179.205.68这样的优雅IP
}
public static String to2(int num){
    StringBuilder sb = new StringBuilder();
    while(num > 0){
        sb.insert(0,""+num % 2);
        num /= 2;
    }
    while(sb.length() < 8){ // 长度改为8
        sb.insert(0, "0");
    }
    return sb.toString();
}

答案

34.179.205.68
34.205.179.68
68.179.205.34
68.205.179.34
179.34.68.205
179.68.34.205
205.34.68.179
205.68.34.179

8种

 

你可能感兴趣的:(力扣,算法,java)