蓝桥杯——试题 算法训练 Bit Compressor

Java代码:

  1 /**
  2  * @Author LZP
  3  * @Date 2021/2/28 10:45
  4  * @Version 1.0
  5  *
  6 试题 算法训练 Bit Compressor
  7 
  8 
  9 资源限制
 10 时间限制:1.0s   内存限制:256.0MB
 11 问题描述
 12   数据压缩的目的是为了减少存储和交换数据时出现的冗余。这增加了有效数据的比重并提高了传输速率。有一种压缩二进制串的方法是这样的:
 13   将连续的n个1替换为n的二进制表示(注:替换发生当且仅当这种替换减少了二进制串的总长度)
 14   (译者注:连续的n个1的左右必须是0或者是串的开头、结尾)
 15   比如:11111111001001111111111111110011会被压缩成10000010011110011。原串长为32,被压缩后串长为17.
 16   这种方法的弊端在于,有时候解压缩算法会得到不止一个可能的原串,使得我们无法确定原串究竟是什么。请你写一个程序来判定我们能否利用压缩后的信息来确定原串。给出原串长L,原串中1的个数N,以及压缩后的串。
 17   L<=16 Kbytes,压缩后的串长度<=40 bits。
 18 输入格式
 19   第一行两个整数L,N,含义同问题描述
 20   第二行一个二进制串,表示压缩后的串
 21 输出格式
 22   输出"YES"或"NO"或"NOT UNIQUE"(不包含引号)
 23   分别表示:
 24   YES:原串唯一
 25   NO:原串不存在
 26   NOT UNIQUE:原串存在但不唯一
 27 样例输入
 28 样例1:
 29 32 26
 30 10000010011110011
 31 样例2:
 32 9 7
 33 1010101
 34 样例3:
 35 14 14
 36 111111
 37 样例输出
 38 样例1:YES
 39 样例2:NOT UNIQUE
 40 样例3:NO
 41 
 42  算法题型:类解压缩
 43  解题方法:递归求解
 44  解题思路:压缩后的字符串已知,可以对压缩后的字符串进行从头到尾遍历,用指针的移动(Java中就是数组的索引)
 45  来讨论所有情况。每当指针指向的字符为'1'时就可以展开进一步的遍历,即将当前索引作为字符串的开始索引,结束
 46  索引初始化为开始索引+1,然后依次递增到压缩后的字符串的长度,在这个过程中,如果发现结尾索引所指向的字符为
 47  '1'的话,就跳过当前循环,因为根据题意可知,前后都为1的字符串不符合压缩条件,所以解压缩时就不用考虑该情况。
 48  也就是说除了前后都为1的这种情况外,还剩下三种情况是我们需要写算法时需要考虑的:
 49     例如:
 50          1) 111110
 51          2) 011110
 52          3) 011111
 53 
 54  这里尤其要注意的一点就是当截取的字符串是“11”,也就是n = 3的时候,因为3这个数非常特别,又因为题目的要求,
 55  当n = 3时,原字符串可能为“111”,也可能为“11”,所以我们这里需要分两种情况讨论,而如果当指针指向的字符为
 56  '0'时则指针向后移动一位,当前字符串的总长度+1,当前字符串的含“1”个数不变继续向下递归。重复该过程,直到当前索引等于压
 57  缩后的字符串的总长度时,结束第一次递归,然后又继续下一次递归,直到所有情况都讨论完毕,程序停止。算法结果得
 58  到输出。
 59  */
 60 public class Main {
 61     // 原字符串长
 62     private static int L;
 63     // 原字符串1的个数
 64     private static int N;
 65     // 压缩后的字符串
 66     private static String str;
 67     // 满足条件的原字符串个数
 68     private static int count;
 69 
 70     public static void main(String[] args) {
 71         Scanner input = new Scanner(System.in);
 72         L = input.nextInt();
 73         N = input.nextInt();
 74         str = input.next();
 75         division(0, 0, 0);
 76         if (count > 1) {
 77             System.out.println("NOT UNIQUE");
 78         } else if (count < 1) {
 79             System.out.println("NO");
 80         } else {
 81             System.out.println("YES");
 82         }
 83     }
 84 
 85     /**
 86      * 32 26
 87      * 10000010011110011
 88      * @param curIndex 当前压缩后字符串的索引
 89      * @param curStrLen 当前字符串的长度
 90      * @param curOneNum 当前字符串中1的个数
 91      */
 92     public static void division(int curIndex, int curStrLen, int curOneNum) {
 93         // 出口
 94         if (curIndex == str.length()) {
 95             if (curStrLen == L && curOneNum == N) {
 96                 count++;
 97             }
 98             return;
 99         }
100         if (curStrLen > L) {
101             return;
102         }
103         if (curOneNum > N) {
104             return;
105         }
106 
107         // 第一个开始字符是1的话,那么就从这个1开始,向后依次遍历
108         if (str.charAt(curIndex) == '1') {
109             for (int i = curIndex; i < str.length(); i++) {
110                 // 如果是“1xxxx1”则不用判断,一定没有这种情况
111                 /*
112                     根据题意:能压缩的只有三种情况
113                         1、111110
114                         2、011110
115                         3、011111
116                  */
117 
118                 // 开头和结尾都是1那么就直接跳过这种情况
119                 if (i + 1 < str.length() && str.charAt(i + 1) == '1') {
120                     continue;
121                 }
122                 int n = getD(str.substring(curIndex, i + 1));
123                 // 注意 “11” 的原字符串可能是 “111” 或者 “11” 所以n = 3时要多分一种情况
124                 /*
125                   如果长度为3,原串可能是111
126                   但如果原串是11,就不需要转换他
127                   所以我们不清楚结果中的11是经过转换的,还是说原来就是这样的
128                   所以分两种情况:
129                  */
130                 if (n == 3) {
131                     // 原串为“11”
132                     division(i + 1, curStrLen + 2, curOneNum + 2);
133                 }
134                 division(i + 1, curStrLen + n, curOneNum + n);
135             }
136         } else {
137             // 如果第一个字符不是1,而是零,则直接指针向后移一位,当前字符串的长度+1
138             division(curIndex + 1, curStrLen + 1, curOneNum);
139         }
140     }
141 
142     /**
143      * 返回对应二进制数的十进制数
144      * @param binStr
145      * @return
146      */
147     public static int getD(String binStr) {
148         int total = 0;
149         for (int i = 0; i < binStr.length(); i++) {
150             if (binStr.charAt(i) == '1') {
151                 total += (long) Math.pow(2, (binStr.length() - 1 - i));
152             }
153         }
154         return total;
155     }
156 }
View Code

 

posted @ 2021-03-05 09:28  没有你哪有我  阅读(88)  评论(0编辑  收藏  举报