簡體   English   中英

使用遞歸反轉句子中的單詞而不是標點符號

[英]Reverse the words in a sentence but not punctuation using recursion

如何使用遞歸來反轉句子中的單詞,而不是標點符號。 據說該句子使用標點符號:,.?!

輸入:“傑克,回家!”

Output:“回家,傑克來了!”

現在我以某種方式設法正確完成了任務,但沒有使用遞歸。 我應該如何將這項工作轉換為使用遞歸來解決問題?

這是方法:

public static StringBuilder reverseSentenceWithPunctuation(String sentence, int i) {
        String[] parts = sentence.split(" ");
        StringBuilder newSentence = new StringBuilder();
        Map<Integer, Character> punctuationMap = new HashMap<>();

        for (int j = 0; j < parts.length; j++) {
            if (parts[j].endsWith(",") || parts[j].endsWith(".") || parts[j].endsWith("!") || parts[j].endsWith("?")) {
                char lastSymbol = parts[j].charAt(parts[j].length()-1);
                punctuationMap.put(j, lastSymbol);
                String changedWord = parts[j].replace(String.valueOf(lastSymbol), "");
                parts[j] = changedWord;
            }
        }

        for (int j = parts.length-1; j >= 0; j--) {
            newSentence.append(parts[j]);
            if (punctuationMap.containsKey(i)) {
                newSentence.append(punctuationMap.get(i));
                newSentence.append(" ");
            } else
                newSentence.append(" ");
            i++;
        }
        return newSentence;
    }

提前致謝!

為了使用遞歸來實現這個任務,應該准備一個匹配第一個和最后一個單詞的模式,然后是一些分隔符:

word1 del1 word2 del2 .... wordLast delLast

在匹配輸入的情況下,結果計算如下:

wordLast del1 REVERT(middle_part) + word1 delLast

示例實現可能如下(單詞被認為包含英文字母和撇號'用於縮寫):

static Pattern SENTENCE = Pattern.compile("^([A-Za-z']+)([^A-Za-z]+)?(.*)([^'A-Za-z]+)([A-Za-z']+)([^'A-Za-z]+)?$");

public static String revertSentence(String sentence) {
    
    Matcher m = SENTENCE.matcher(sentence);
    if (m.matches()) {
        return m.group(5) + (m.group(2) == null ? "" : m.group(2)) 
            + revertSentence(m.group(3) + m.group(4)) // middle part
            + m.group(1) + (m.group(6) == null ? "" : m.group(6));
    }
    return sentence;
}

測試:

System.out.println(revertSentence("Jack, come home!"));
System.out.println(revertSentence("Jack, come home please!!"));
System.out.println(revertSentence("Jane cried: Will you come home Jack, please, don't go!"));

Output:

home, come Jack!
please, home come Jack!!
go don't: please Jack home come you, Will, cried Jane!

我認為這不是遞歸 function 的好案例,主要是因為您需要 2 個循環。 此外,一般來說,迭代算法在性能方面更好,並且不會引發 stackoverflow 異常。

所以我認為使用遞歸函數的主要原因是可讀性和易用性,老實說,在這種情況下,我認為它不值得。

無論如何,這是我將您的代碼轉換為遞歸 function 的嘗試。 如前所述,由於有 2 個循環,我使用了 2 個函數。 我確信有一種方法可以使用單個 function 來實現這一點,它首先加載 map 的標點符號,然后組成最終的字符串,但老實說這會很丑陋。

import java.util.*;
import java.util.stream.*;

public class HelloWorld{

    static Character[] punctuationCharacters = {',','.','!'};

    public static void main(String []args){
        System.out.println(reverseSentenceWithPunctuation("Jack, come home!"));
    }
     
    private static String reverseSentenceWithPunctuation(String sentence) {
        
        String[] parts = sentence.split(" ");

        return generate(0, parts, extractPunctuationMap(0, parts));
    }
     
    private static Map<Integer, Character> extractPunctuationMap(int index, String[] parts){
        Map<Integer, Character> map = new HashMap<>();
        if (index >= parts.length) {
            return map;
        }
        char lastSymbol = parts[index].charAt(parts[index].length() - 1);
        if (Arrays.stream(punctuationCharacters).anyMatch(character -> character == lastSymbol)) {
            parts[index] = parts[index].substring(0, parts[index].length() - 1);
            map = Stream.of(new Object[][] { 
             { index,  lastSymbol}
            }).collect(Collectors.toMap(data -> (Integer) data[0], data -> (Character) data[1]));
        }
        map.putAll(extractPunctuationMap(index + 1, parts));
        return map;
    }
    
    private static String generate(int index, String[] parts, Map<Integer, Character> punctuationMap) {
        
        if (index >= parts.length) {
            return "";
        }
        String part = index == 0? " " + parts[index] : parts[index];
        if (punctuationMap.containsKey(parts.length -1 - index)) {
            part += punctuationMap.get(parts.length -1 - index);
        }
        return generate(index + 1, parts, punctuationMap) + part;
        
    }
}

在偽代碼中可能是這樣的:

  1. 把整個句子

(一個)。 得到第一個詞

(b)。 得到最后一句話

(如果第一個或最后一個單詞后有標點符號,請留在那里)

  1. 交換(a,b)並返回句子的剩余中間部分
  2. 重復(1)和(2)直到只有兩個詞或一個
  3. 返回剩下的最后兩個(交換的)單詞(如果是一個單詞,就返回那個)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM