替换所有重复两次或三次的字母为单个字母。

huangapple go评论58阅读模式
英文:

Replace all doubled or tripled letters with single ones

问题

public static String doubleLetters(String str) {
    StringBuilder ret = new StringBuilder(str.length());
    if (str.length() == 0) return "";

    for (int i = 0; i < str.length(); i++) {
        if (i < str.length() - 2 && str.charAt(i) == str.charAt(i + 1) && str.charAt(i) == str.charAt(i + 2)) {
            ret.append(str.charAt(i));
            i += 2; // Skip the next two identical characters
        } else if (i < str.length() - 1 && str.charAt(i) == str.charAt(i + 1)) {
            ret.append(str.charAt(i));
            i++; // Skip the next identical character
        } else {
            ret.append(str.charAt(i));
        }
    }
    return ret.toString();
}
英文:

Task:

> For a given string of characters consisting only of letters: a, b and
> c swap all doubled or tripled letters for single ones

I prepared such a code:

public static String doubleLetters(String str) {
        StringBuilder ret = new StringBuilder(str.length());
        if (str.length() == 0) return &quot;&quot;;

        for (int i = 1; i &lt; str.length(); i++)
        {
            if(str.charAt(i) == str.charAt(i-1) 
                    || str.charAt(i) == str.charAt(i-1) &amp;&amp; str.charAt(i) == str.charAt(i-2))
            {
                ret.append(str.charAt(i));
            }
        }
        return ret.toString();
    }

However, I cannot define the condition to take into account tripled letters.

> By entering "aaabbbccc" I want "abc".

> By entering "aabbcc" I want "abc".

> By entering "aaaaabbbbbbbccc" I want "aabbbc".

IMPORTANT
Letters that are converted to 1 letter are not taken into account.

Please help me how to approach this problem.

答案1

得分: 2

以下是代码的翻译部分:

public static String eliminateMultipleLetters(String s) {
    StringBuilder sb = new StringBuilder(); // 用于循环的更好方式是StringBuilder,而不是字符串连接
    for (int i = 0; i < s.length() - 1; i++) {
        if (s.charAt(i) != s.charAt(i + 1))
            sb.append(s.charAt(i));
    }
    sb.append(s.charAt(s.length() - 1)); // 添加最后一个字符
    return sb.toString();
}

Edit: 要替换3个字符为1个字符只要有3个字符然后如果可能的话就是2个字符你可以按照以下方式操作逻辑非常相似只是最后一步变得更加复杂):

public static String replace3or2Letters(String s) {
    if (s.length() < 2)
        return s;
    StringBuilder sb = new StringBuilder();
    int i;
    for (i = 0; i < s.length() - 2; i++) {
        sb.append(s.charAt(i));
        if (s.charAt(i) == s.charAt(i + 1)) {
            if (s.charAt(i) == s.charAt(i + 2))
                i += 2;
            else
                i++;
        }
    }
    if (i == s.length() - 2) {
        sb.append(s.charAt(s.length() - 2));
        if (s.charAt(s.length() - 2) != s.charAt(s.length() - 2))
            sb.append(s.charAt(s.length() - 1));
    } else if (i == s.length() - 1) {
        sb.append(s.charAt(s.length() - 1));
    }
    return sb.toString();
}

更加优雅的方式

public static String replaceUpToXbySingle(String s, int x) { // x = 3 for you
    StringBuilder sb = new StringBuilder();
    char last = 'c'; // 无论如何
    int count = 0;
    for (int i = 0; i < s.length(); i++) {
        if (count == 0 || s.charAt(i) != last) {
            if (count > 0)
                sb.append(last);
            last = s.charAt(i);
            count = 1;
        } else if (++count == x) {
            sb.append(last);
            count = 0;
        }
    }
    if (count > 0)
        sb.append(last);
    return sb.toString();
}
英文:

It is not entirely clear whether you want to replace only triple or double letters or a repeated character of any length by a single one. I'm assuming the latter one:

public static String eliminateMultipleLetters(String s) {
StringBuilder sb = new StringBuilder(); // better for loops than concatenation
for (int i = 0; i &lt; s.length() - 1; i++) {
if (s.charAt(i) != s.charAt(i + 1))
sb.append(s.charAt(i));
}
sb.append(s.charAt(s.length() - 1)); // append last character
return sb.toString();
}

Edit: to replace 3 characters by 1 as long as there are 3 and then 2 if possible, you could do as follows (the logic is very similar, just the step at the end gets more complicated):

public static String replace3or2Letters(String s) {
if (s.length() &lt; 2)
return s;
StringBuilder sb = new StringBuilder();
int i;
for (i = 0; i &lt; s.length() - 2; i++) {
sb.append(s.charAt(i));
if (s.charAt(i) == s.charAt(i + 1)) {
if (s.charAt(i) == s.charAt(i + 2))
i += 2;
else
i++;
}
}
if (i == s.length() - 2) {
sb.append(s.charAt(s.length() - 2));
if (s.charAt(s.length() - 2) != s.charAt(s.length() - 2))
sb.append(s.charAt(s.length() - 1));
} else if (i == s.length() - 1) {
sb.append(s.charAt(s.length() - 1));
}
return sb.toString();
}

More elegant:

public static String replaceUpToXbySingle(String s, int x) { // x = 3 for you
StringBuilder sb = new StringBuilder();
char last = &#39;c&#39;; // whatever
int count = 0;
for (int i = 0; i &lt; s.length(); i++) {
if (count == 0 || s.charAt(i) != last) {
if (count &gt; 0)
sb.append(last);
last = s.charAt(i);
count = 1;
} else if (++count == x) {
sb.append(last);
count = 0;
}
}
if (count &gt; 0)
sb.append(last);
return sb.toString();
}

答案2

得分: 1

以下是更新后的回复中的翻译部分:

如果您想替换三个一组然后两个一组的组合您需要构建一个连续频率的列表在拥有这个列表之后您可以通过对总数应用div/mod逻辑来构建一个字符串

我包括了一个扩展`Map.Entry``Pair`它存储键值关联

```java
import java.util.*;

public class StringUtil {
    public static void main(String[] args) {
        System.out.println(dedupe(&quot;aabbcc&quot;).equals(&quot;abc&quot;));
        System.out.println(dedupe(&quot;aaabbbccc&quot;).equals(&quot;abc&quot;));
        System.out.println(dedupe(&quot;aaaaabbbbbbbccc&quot;).equals(&quot;aabbbc&quot;));
    }

    public static String dedupe(String str) {
        if (str == null || str.isEmpty()) {
            return str;
        }

        StringBuilder buffer = new StringBuilder();
        List&lt;Pair&lt;Character, Integer&gt;&gt; pairs = new ArrayList&lt;&gt;();
        char[] chars = str.toCharArray();
        char curr, prev = chars[0];
        int total = 0, i, add3, add2;

        for (i = 1; i &lt; chars.length; i++) {
            curr = chars[i];
            total++;
            if (curr != prev) {
                pairs.add(new Pair&lt;&gt;(prev, total));
                total = 0;
                prev = curr;
            }
        }
        total++;
        pairs.add(new Pair&lt;&gt;(prev, total));

        for (Pair&lt;Character, Integer&gt; pair : pairs) {
            total = pair.getValue();
            add3 = total / 3;
            for (i = 0; i &lt; add3; i++) {
                buffer.append(pair.getKey());
            }
            total %= 3;
            add2 = total / 2;
            for (i = 0; i &lt; add2; i++) {
                buffer.append(pair.getKey());
            }
            total %= 2;
            for (i = 0; i &lt; total; i++) {
                buffer.append(pair.getKey());
            }
        }
        return buffer.toString();
    }

    private static final class Pair&lt;K, V&gt; implements Map.Entry&lt;K, V&gt; {
        private final K key;
        private V value;

        public Pair(K key, V value) {
            this.key = key;
            this.value = value;
        }

        @Override
        public K getKey() {
            return key;
        }

        @Override
        public V getValue() {
            return value;
        }

        @Override
        public V setValue(V value) {
            V old = this.value;
            this.value = value;
            return old;
        }
    }
}

英文:

Updated response

If you want to replace groups of three, followed by groups of two, you need to build a list of contiguous frequencies. After you have this list, you could build a string by applying div/mod logic to the total.

I included a Pair class that extends Map.Entry which stores key-value associations.

import java.util.*;

public class StringUtil {
    public static void main(String[] args) {
        System.out.println(dedupe(&quot;aabbcc&quot;).equals(&quot;abc&quot;));
        System.out.println(dedupe(&quot;aaabbbccc&quot;).equals(&quot;abc&quot;));
        System.out.println(dedupe(&quot;aaaaabbbbbbbccc&quot;).equals(&quot;aabbbc&quot;));
    }

    public static String dedupe(String str) {
        if (str == null || str.isEmpty()) {
            return str;
        }

        StringBuilder buffer = new StringBuilder();
        List&lt;Pair&lt;Character, Integer&gt;&gt; pairs = new ArrayList&lt;&gt;();
        char[] chars = str.toCharArray();
        char curr, prev = chars[0];
        int total = 0, i, add3, add2;

        for (i = 1; i &lt; chars.length; i++) {
            curr = chars[i];
            total++;
            if (curr != prev) {
                pairs.add(new Pair&lt;&gt;(prev, total));
                total = 0;
                prev = curr;
            }
        }
        total++;
        pairs.add(new Pair&lt;&gt;(prev, total));

        for (Pair&lt;Character, Integer&gt; pair : pairs) {
            total = pair.getValue();
            add3 = total / 3;
            for (i = 0; i &lt; add3; i++) {
                buffer.append(pair.getKey());
            }
            total %= 3;
            add2 = total / 2;
            for (i = 0; i &lt; add2; i++) {
                buffer.append(pair.getKey());
            }
            total %= 2;
            for (i = 0; i &lt; total; i++) {
                buffer.append(pair.getKey());
            }
        }
        return buffer.toString();
    }

    private static final class Pair&lt;K, V&gt; implements Map.Entry&lt;K, V&gt; {
        private final K key;
        private V value;

        public Pair(K key, V value) {
            this.key = key;
            this.value = value;
        }

        @Override
        public K getKey() {
            return key;
        }

        @Override
        public V getValue() {
            return value;
        }

        @Override
        public V setValue(V value) {
            V old = this.value;
            this.value = value;
            return old;
        }
    }
}

Original response

All you would need to do it store a previous (prev) value and then just loop over the characters and append to buffer if current (curr) does not match the previous.

public class StringUtil {
    public static void main(String[] args) {
        System.out.println(dedupe(&quot;aaabbbccc&quot;)); // &quot;abc&quot;
    }

    public static String dedupe(String str) {
        StringBuilder buffer = new StringBuilder();
        char prev = 0;

        for (char curr : str.toCharArray()) {
            if (curr != prev) {
                buffer.append(curr);
                prev = curr;
            }
        }

        return buffer.toString();
    }
}

答案3

得分: 1

另一种方法:计算字符连续出现的次数,然后通过将它们的数量除以三来批量打印。

    public static String doubleLetters(String str) {
        StringBuilder ret = new StringBuilder(str.length());
        if (str.length() == 0) return "";

        int count = 1;
        for (int i = 1; i < str.length(); i++) {
            if (str.charAt(i) == str.charAt(i-1)) {
                count++;
                continue;
            }
            for (; count > 0; count -= 3)
                ret.append(str.charAt(i-1));
            count = 1;
        }
        for (; count > 0; count -= 3)
            ret.append(str.charAt(str.length() - 1));
        return ret.toString();
    }
英文:

Another approach: count the number of consecutive occurrences of a character, and then print them in bulk, by dividing their number by three.

public static String doubleLetters(String str) {
StringBuilder ret = new StringBuilder(str.length());
if (str.length() == 0) return &quot;&quot;;
int count = 1;
for (int i = 1; i &lt; str.length(); i++)
{
if (str.charAt(i) == str.charAt(i-1)) {
count++;
continue;
}
for (; count &gt; 0; count -= 3)
ret.append(str.charAt(i-1));
count = 1;
}
for (; count &gt; 0; count -= 3)
ret.append(str.charAt(str.length() - 1));
return ret.toString();
}    

答案4

得分: 0

然而,我无法定义考虑重复字母的条件。

通过输入"aaabbbccc",我想得到"abc"。

通过输入"aabbcc",我想得到"abc"。

通过输入"aaaaabbbbbbbccc",我想得到"aabbbc"。

重要提示:转换为1个字母的字母不被考虑在内。

想象一下这个问题分为三个阶段:

  • 首先,生成输入中所有单个、双重或三重字母出现的序列(或流)。
  • 接下来,将序列中的每个出现替换为其第一个字母。
  • 最后,将序列(或流)重新组合成一个单一的字符串实例。

为了使这个解决方案更易读,我会使用一个主方法和一个静态的帮助方法,如下所示:

public static String deDupe(String input) {
    String result = generateStreamOfOccurrences(input)
        .map(occurrence -> occurrence.substring(0, 1))
        .collect(Collectors.joining());
    return result;
}

private static Stream<String> generateStreamOfOccurrences(String str) {
    String input = str;
    List<String> listOfOccs = new ArrayList<>();

    if (input != null) {
        while (input.length() > 0) {
            String occ = input.substring(0, 1);

            if (input.length() > 2 && input.substring(1, 3).equals(occ + occ)) {
                occ = input.substring(0, 3);
            }
            else if (input.length() > 1 && input.substring(1, 2).equals(occ)) {
                occ = input.substring(0, 2);
            }

            input = input.substring(occ.length());
            listOfOccs.add(occ);
        }
    }
    return listOfOccs.stream();        
}

主函数很容易阅读。它获取了一个包含字符串中的字母出现次数的流,每个出现次数都是其第一个字母的单个、双重或三重。获取这个 Stream<String> 管道的工作封装在辅助函数 generateListOfOccurrences() 中。然后,流中的每个元素都被替换为只包含第一个字母的元素。然后它们被连接在一起形成结果。

英文:

> However, I cannot define the condition to take into account tripled
> letters.
>
> By entering "aaabbbccc" I want "abc".
>
> By entering "aabbcc" I want "abc".
>
> By entering "aaaaabbbbbbbccc" I want "aabbbc".
>
> IMPORTANT Letters that are converted to 1 letter are not taken into
> account.

Imagine this problem in three stages:

  • First, generate a sequence (or a stream) of all the single, double, or triple letter occurrences in your input
  • Next, replace each of the occurrences in the sequence with its first letter
  • Finally, put the sequence (or stream) back together into a single String instance

To realize this solution very readably, I would use a main method and a static helper method as follows:

public static String deDupe(String input) {
String result = generateStreamOfOccurrences(input)
.map(occurrence -&gt; occurrence.substring(0, 1)
.collect(Collectors.joining());
return result;
}
private static Stream&lt;String&gt; generateStreamOfOccurrences(String str) {
String input = str;
List&lt;String&gt; listOfOccs = new ArrayList&lt;&gt;();
if (input != null) {
while (input.length() &gt; 0) {
String occ = input.substring(0, 1);
if (input.length() &gt; 2 &amp;&amp; input.substring(1, 3).equals(occ + occ)) {
occ = input.substring(0, 3);
}
else if (input.length() &gt; 1 &amp;&amp; input.substring(1, 2).equals(occ)) {
occ = input.substring(0, 2);
}
input = input.substring(occ.length());
listOfOccs.add(occ);
}
}
return listOfOccs.stream();        
}

The main function is easy to read. It obtains a stream of letter occurrences in the String, each of which is a single, double, or triple of its first letter. The work of obtaining this Stream&lt;String&gt; pipeline is encapsulated in the helper function generateListOfOccurrences(). Then each of the elements in the stream are replaced by elements that consist of just the 1st letter. Then they are joined together to form the result.

答案5

得分: 0

然而,我无法定义考虑三重字母的条件。

通过输入"aaabbbccc",我想要得到"abc"。

通过输入"aabbcc",我想要得到"abc"。

通过输入"aaaaabbbbbbbccc",我想要得到"aabbbc"。

重要的是,转换为一个字母的字母不会被考虑在内。

想象一下这个问题分为三个阶段:

  • 首先,生成输入中所有单个、双重或三重字母出现的序列(或流)。
  • 接下来,用序列中每个出现的第一个字母替换它。
  • 最后,将序列(或流)重新组合成一个字符串实例。

要以非常可读的方式实现这个解决方案,我会使用一个主方法和一个静态的辅助方法,如下所示:

public static String deDupe(String input) {
    String result = generateStreamOfOccurrences(input)
        .map(occurrence -> occurrence.substring(0, 1))
        .collect(Collectors.joining());
    return result;
}

private static Stream<String> generateStreamOfOccurrences(String input) {
    List<String> listOfOccs = new ArrayList<>();

    if (input != null) {
        while (input.length() > 0) {
            String occ = input.substring(0, 1);

            if (input.length() > 2 && input.substring(1, 3).equals(occ + occ))
                occ = input.substring(0, 3);
            if (input.length() > 1 && input.substring(1, 2).equals(occ))
                occ = input.substring(0, 2);

            input = input.substring(occ.length());
            listOfOccs.add(occ);
        }
    }
    return listOfOccs.stream();        
}

主函数易于阅读。它获得一个字符串中的字母出现的流,每个出现都是其第一个字母的单个、双重或三重。获得这个Stream<String>管道的工作被封装在辅助函数generateListOfOccurrences()中。

英文:

> However, I cannot define the condition to take into account tripled
> letters.
>
> By entering "aaabbbccc" I want "abc".
>
> By entering "aabbcc" I want "abc".
>
> By entering "aaaaabbbbbbbccc" I want "aabbbc".
>
> IMPORTANT Letters that are converted to 1 letter are not taken into
> account.

Imagine this problem in three stages:

  • First, generate a sequence (or a stream) of all the single, double, or triple letter occurrences in your input
  • Next, replace each of the occurrences in the sequence with its first letter
  • Finally, put the sequence (or stream) back together into a single String instance

To realize this solution very readably, I would use a main method and a static helper method as follows:

public static String deDupe(String input) {
String result = generateStreamOfOccurrences(input)
.map(occurrence -&gt; occurrence.substr(0, 1)
.collect(Collectors.joining());
return result;
}
private static Stream&lt;String&gt; generateStreamOfOccurrences(String input) {
List&lt;String&gt; listOfOccs = new ArrayList&lt;&gt;();
if (input != null) {
while (input.length() &gt; 0) {
String occ = input.substring(0, 1);
if (input.length() &gt; 2 &amp;&amp; input.substring(1, 3).equals(occ + occ))
occ = input.substring(0, 3);
if (input.length() &gt; 1 &amp;&amp; input.substring(1, 2).equals(occ))
occ = input.substring(0, 2);
input = input.substring(occ.length());
listOfOccs.add(occ);
}
}
return listOfOccs.stream();        
}

The main function is easy to read. It obtains a stream of letter occurrences in the String, each of which is a single, double, or triple of its first letter. The work of obtaining this Stream&lt;String&gt; pipeline is encapsulated in the helper function generateListOfOccurrences().

huangapple
  • 本文由 发表于 2020年10月15日 20:30:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/64371611.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定