前提知识
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) {
Listlist = 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候选项
Listlist = 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个数字)
ListresList = 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种