当前位置: 首页 > 知识库问答 >
问题:

检查是否可以对二进制字符串进行分区,使每个分区为5的幂

曹焱
2023-03-14

我最近遇到了这个问题--给定一个二进制字符串,检查我们是否可以将字符串分割成0..n个部分,使每个部分都是5的次方。返回拆分的最小数目,如果可以的话。

例如:

input = "101101" - returns 1, as the string can be split once to form "101" and "101",as 101= 5^1.
input = "1111101" - returns 0, as the string itself is 5^3.
input = "100"- returns -1, as it can't be split into power(s) of 5.

我想出了这个递归算法

  1. 检查字符串本身是否为5的幂。如果是,则返回0
  2. 否则,逐个字符迭代字符串,在每个点检查到目前为止看到的数字是否是5的幂。如果是,将1添加到split count,并从步骤1开始递归检查字符串的其余部分是否为5的幂。
  3. 返回到目前为止看到的最小拆分数。

我在Java实施了上述algo。我相信它工作正常,但它是一个简单的递归解决方案。是否可以使用动态编程来改善运行时间?

代码如下:

public int partition(String inp){
    if(inp==null || inp.length()==0)
        return 0;
    return partition(inp,inp.length(),0);
}
public int partition(String inp,int len,int index){
    if(len==index)
        return 0;
    if(isPowerOfFive(inp,index))
        return 0;
    long sub=0;
    int count = Integer.MAX_VALUE;
    for(int i=index;i<len;++i){
        sub = sub*2 +(inp.charAt(i)-'0');
        if(isPowerOfFive(sub))
            count = Math.min(count,1+partition(inp,len,i+1));
    }
    return count;
}

帮助程序函数:

public boolean isPowerOfFive(String inp,int index){
    long sub = 0;
    for(int i=index;i<inp.length();++i){
        sub = sub*2 +(inp.charAt(i)-'0');
    }
    return isPowerOfFive(sub);
}

public boolean isPowerOfFive(long val){
    if(val==0)
        return true;
    if(val==1)
        return false;
    while(val>1){
        if(val%5 != 0)
            return false;
        val = val/5;
    }
    return true;
}

共有2个答案

应翰飞
2023-03-14

不是计算所有可能的子字符串,您可以检查5的幂的二进制表示,以搜索一个公共模式。使用类似于:

bc <<< "obase=2; for(i = 1; i < 40; i++) 5^i"

你得到:

51=1012=110012
54=10011100012
55=1100001101012
56=111101000010012
57=1001101001011012UB>
...
529=101000011000111100011111010111001101010111001000010111110010101010102

如您所见,5的奇数次幂总是以101结尾,5的偶数次幂总是以模式10+1结尾(其中+表示一次或多次出现)。

您可以将输入字符串放入一个trie中,然后对其进行迭代,识别10+1模式,一旦匹配,就对其进行计算,检查是否为假阳性。

牛嘉谊
2023-03-14

以下是可以做的简单改进:

  • 在开始之前计算5的所有幂,这样可以更快地进行检查。
  • 如果拆分次数已大于您已完成的最佳拆分次数,则停止拆分输入字符串。

下面是我使用这些想法的解决方案:

public static List<String> powers = new ArrayList<String>();
public static int bestSplit = Integer.MAX_VALUE;

public static void main(String[] args) throws Exception {
    // input string (5^5, 5^1, 5^10)
    String inp = "110000110101101100101010000001011111001";
    // calc all powers of 5 that fits in given string
    for (int pow = 1; ; ++pow) {
        String powStr = Long.toBinaryString((long) Math.pow(5, pow));
        if (powStr.length() <= inp.length()) { // can be fit in input string
            powers.add(powStr);
        } else {
            break;
        }
    }
    Collections.reverse(powers); // simple heuristics, sort powers in decreasing order
    // do simple recursive split
    split(inp, 0, -1);
    // print result
    if (bestSplit == Integer.MAX_VALUE) {
        System.out.println(-1);
    } else {
        System.out.println(bestSplit);
    }
}

public static void split(String inp, int start, int depth) {
    if (depth >= bestSplit) {
        return; // can't do better split
    }
    if (start == inp.length()) { // perfect split
        bestSplit = depth;
        return;
    }
    for (String pow : powers) {
        if (inp.startsWith(pow, start)) {
            split(inp, start + pow.length(), depth + 1);
        }
    }
}

我还发现了另一种看起来非常快的方法。

  1. 计算字符串表示形式小于input字符串的5的所有幂。将这些字符串保存在powers数组中。
  2. 对于来自powers数组的每个字符串power:如果powerinput的子字符串,则将其startend索引保存到edges数组(元组数组)中。
  3. 现在我们只需要从edges数组中的边找到从索引0到索引input.length()的最短路径。每个边具有相同的权重,因此使用BFS可以非常快地找到最短路径。
  4. 找到的最短路径中的边数正是您所需要的--输入字符串的最小拆分数。
 类似资料:
  • 我正在进行排序,并希望控制alpha值的cmp不区分大小写(即。https://perl6.org/archive/rfc/143.html). 有没有:我可能是这个的副词?

  • 问题内容: 我想编写一个Java方法,如果字符串是回文,则返回true。 这是我到目前为止的内容: 我的问题是,它不考虑像这样的单词:回文。 在不区分大小写并忽略标点符号的情况下,测试这是否是回文式的最佳方法是什么。 问题答案: 使用此正则表达式删除所有标点和空格并将其转换为小写

  • 如何根据列中项数的计数来分区DataFrame。假设我们有一个包含100人的DataFrame(列是和),我们希望为一个国家中的每10个人创建一个分区。 如果我们的数据集包含来自中国的80人,来自法国的15人,来自古巴的5人,那么我们需要8个分区用于中国,2个分区用于法国,1个分区用于古巴。 下面是无法工作的代码: null 有什么方法可以动态设置每个列的分区数吗?这将使创建分区数据集变得更加容易

  • 本文向大家介绍MySQL查询以字符串字段中的数字字符对行进行分组?,包括了MySQL查询以字符串字段中的数字字符对行进行分组?的使用技巧和注意事项,需要的朋友参考一下 为此,您可以在+运算符的帮助下将0与字符串字段连接起来。这里的场景就像我们需要从字符串字段“ 9844Bob ”中获取数字“ 9844 ”。 让我们首先创建一个表- 使用插入命令在表中插入一些记录- 使用select语句显示表中的所

  • 我读过spring batch中的分区,我发现了一个演示分区的示例。该示例从CSV文件中读取人员,进行一些处理,并将数据插入数据库。在本例中,1 partitioning=1 file,因此partitioner实现如下所示: 但如果我有一个10TB的文件呢?spring批处理是否允许以某种方式对其进行分区? 我尝试了以下方法来实现我的目标: 分为两步——第一步将文件分成若干部分,第二步处理第一步

  • 问题内容: 如何在Java 8 Stream上实现“分区”操作?划分是指将流分成给定大小的子流。它在某种程度上与Guava Iterators.partition()方法相同,只是希望分区是延迟评估的Streams,而不是List的Streams。 问题答案: 将任意源流划分为固定大小的批次是不可能的,因为这会加重并行处理。并行处理时,你可能不知道拆分后的第一个子任务中有多少个元素,因此你无法为下