【问题标题】:Exporting specific pattern of string using split method in a most efficient way以最有效的方式使用 split 方法导出字符串的特定模式
【发布时间】:2014-01-17 02:45:43
【问题描述】:

我想在字符串变量中导出位流模式。假设我们的比特流类似于 bitStream="111000001010000100001111"。我正在寻找一种 Java 代码,以将所有连续的“0”或“1”保存在一个数组元素中的方式将此位流保存在特定数组(假设为 bitArray)中。在此示例中,输出将是这样的:

bitArray[0]="111"
bitArray[1]="00000"
bitArray[2]="1"
bitArray[3]="0"
bitArray[4]="1"
bitArray[5]="0000"
bitArray[6]="1"
bitArray[7]="0000"
bitArray[8]="1111"

我想使用 bitArray 来计算存储在每个连续流中的位数。例如,在这种情况下,最终输出将是“3,5,1,1,1,4,1,4,4”。我发现可能“拆分”方法可以为我解决这个问题。但我不知道什么分割模式会为我做这件事,如果我使用bitStream.split("1+"),它会在连续的“1”模式上分割,如果我使用bitStream.split("0+"),它会在连续的“0”的基础上做到这一点,但它会如何基于两者?

Mathew 提出了这个解决方案,它很有效:

var wholeString = "111000001010000100001111";
wholeString = wholeString.replace('10', '1,0');
wholeString = wholeString.replace('01', '0,1');
stringSplit = wholeString.split(',');

我的问题是“这个解决方案是最有效的吗?”

【问题讨论】:

  • 您的结果是否必须有序?例如,bitArray[1] 是否可以包含 111bitArray[0] 是否包含 00000
  • 是的,与出场顺序相同。
  • 关于效率的问题,我认为用小于 O(n) 的复杂度来做是不可能的,因为你必须以某种方式至少评估所有字符串
  • 查看我的答案,了解我对列出的 4 个答案进行的小型性能测试的结果。

标签: java string methods pattern-matching


【解决方案1】:

尝试将任何出现的“01”和“10”分别替换为“0,1”和“1,0”。然后在注入逗号后,使用逗号作为分隔符拆分字符串。

String wholeString = "111000001010000100001111"

wholeString = wholeString.replace("10", "1,0");
wholeString = wholeString.replace("01", "0,1");

String stringSplit[] = wholeString.split(",");

【讨论】:

  • 感谢 Martijn 将我的 JS 翻译成 Java。我从逻辑上知道如何完成它,只是不熟悉 Java 与 JS 的确切细微差别。尝试使用我知道的至少相似的语言。
【解决方案2】:

你可以用一个简单的正则表达式来做到这一点。它匹配 1 和 0,并将按照它们在流中出现的顺序返回它们。如何存储或操作结果取决于您。这是一些示例代码。

String testString = "111000001010000100001111";

Pattern pattern = Pattern.compile("1+|0+");
Matcher matcher = pattern.matcher(testString);

while (matcher.find())
{
    System.out.print(matcher.group().length());
    System.out.print(" ");
}

这将导致以下输出:

3 5 1 1 1 4 1 4 4

存储结果的一个选项是将它们放入ArrayList<Integer>

由于 OP 想要最高效,我做了一些测试,看看每个答案需要多长时间来迭代一个大流 10000 次,并得出以下结果。在每次测试中,时间都不同,但从最快到最慢的顺序保持不变。我知道滴答性能测试存在诸如不考虑系统负载之类的问题,但我只想快速测试一下。

My answer completed in 1145 ms
Alessio's answer completed in 1202 ms
Matthew Lee Keith's answer completed in 2002 ms
Evgeniy Dorofeev's answer completed in 2556 ms

希望对你有帮助

【讨论】:

    【解决方案3】:

    我不会给你代码,但我会引导你找到一个可能的解决方案:

    构造一个ArrayList<Integer>,迭代位数组,只要你有1,增加一个计数器,一旦你有0,就将计数器添加到ArrayList。在此过程之后,您将拥有一个包含数字等的 ArrayList:[1,2,2,3,4] - 表示一系列 1 和 0。
    这将表示 1 和 0 的序列。然后你构造一个ArrayList大小的数组,并相应地填充它。

    时间复杂度为 O(n),因为您只需要在数组上迭代一次。

    【讨论】:

    • 也许我也应该在比特流以“0”开头的情况下这样做。但这是最有效的答案吗?因为在我的情况下,“n”以及调用此方法的次数非常多。
    • 没有。你以任何方式做到这一点。您只需要有一个标志来指示位数组中的第一个数字是什么。
    【解决方案4】:

    此代码适用于任何字符串和模式,而不仅仅是 1 和 0。逐个字符迭代,如果当前字符等于前一个字符,则将最后一个字符附加到列表的最后一个元素,否则在列表中创建一个新元素。

    public List<String> getArray(String input){
    
        List<String> output = new ArrayList<String>();
        if(input==null || input.length==0) return output;
        int count = 0;
        char [] inputA = input.toCharArray();
        output.add(inputA[0]+"");
        for(int i = 1; i <inputA.length;i++){
            if(inputA[i]==inputA[i-1]){
                String current = output.get(count)+inputA[i];
                output.remove(count);
                output.add(current);
            }
            else{
                output.add(inputA[i]+"");
                count++;
            }
        }
        return output;
    }
    

    【讨论】:

      【解决方案5】:

      试试这个

          String[] a = s.replaceAll("(.)(?!\\1)", "$1,").split(",");
      

      【讨论】:

        【解决方案6】:

        我尝试实现@Maroun Maroun 解决方案。

        public static void main(String args[]){
            long start = System.currentTimeMillis();
            String bitStream ="0111000001010000100001111";
            int length = bitStream.length();
            char base = bitStream.charAt(0);
            ArrayList<Integer> counts = new ArrayList<Integer>();
            int count = -1;
            char currChar = ' ';
            for (int i=0;i<length;i++){
                currChar = bitStream.charAt(i);
                if (currChar == base){
                    count++;
                }else {
                    base = currChar;
                    counts.add(count+1);
                    count = 0;
                }
            }
            counts.add(count+1);
            System.out.println("Time taken :" + (System.currentTimeMillis()-start ) +"ms");
            System.out.println(counts.toString());
        }
        

        我相信这是更有效的方式,正如他所说的 O(n) ,你只迭代一次。由于获得计数的目标只是不将其存储为数组。我会推荐这个。即使我们使用正则表达式(内部也必须以任何方式迭代)

        结果输出是

        Time taken :0ms
        [1, 3, 5, 1, 1, 1, 4, 1, 4, 4]
        

        【讨论】:

        • 尝试用 >= 10000 次迭代和更长的流字符串将该解决方案包装在一个循环中。这将提供比仅 0 更好的缩放时序结果。确保仅在外部性能循环中包含所需的项目,可以在该循环之外完成时序和设置。
        【解决方案7】:

        试试这个:

        String[] parts = input.split("(?<=1)(?=0)|(?<=0)(?=1)");
        

        在这里查看实际操作:http://rubular.com/r/qyyfHNAo0T

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-11-13
          • 2017-10-22
          • 2023-03-20
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多