【问题标题】:Check if all characters of string contains same number of times检查字符串的所有字符是否包含相同的次数
【发布时间】:2025-12-29 15:10:16
【问题描述】:

我正在处理以下问题陈述:

如果字符串的所有字符看起来都相同,则该字符串是有效的 次数。如果我们可以只删除 1 个字符,这也是有效的 字符串中的 1 个索引,其余字符将出现 相同的次数。给定一个字符串 s,判断它是否有效。如果 所以,返回YES,否则返回NO。

例如,如果s=abc,它是一个有效的字符串,因为频率是 {a:1,b:1,c:1}s=abcc 也是如此,因为我们可以删除一个 c 和 在剩余的字符串中每个字符都有 1 个。如果s=abccc 但是,该字符串无效,因为我们只能删除 1 次出现 c。这将留下{a:1,b:1,c:2} 的字符频率。

我想出了下面的代码,但它没有按预期工作,并且在此输入 abcdefghhgfedecba 上失败。它正在打印“NO”,但该输入应该是“YES”。

private static String isValid(String s) {
    if (s == null || s.equals("")) {
        return "NO";
    }
    Map<Character, Integer> frequencies = new HashMap<>();
    for (char ch : s.toLowerCase().toCharArray())
        frequencies.put(ch, frequencies.getOrDefault(ch, 0) + 1);

    int count = 0;
    // Iterating over values only
    for (Integer value : frequencies.values()) {
        if (value == 2) {
            count++;
        }
    }
    if (count >= 1) {
        return "YES";
    }
    return "NO";
}

我在这里做错了什么?最好和最有效的方法是什么?

【问题讨论】:

标签: java algorithm data-structures hashmap


【解决方案1】:

计算频率是正确的想法,尽管我不确定您为什么要检查地图中的值是否为2。计算完这些频率后,我将创建具有每个频率的字符数量的反向映射,然后:

  1. 如果地图的大小为 1,则表示所有字符的频率相同 - 字符串有效。
  2. 如果集合的大小为 2:
    • 如果最小频率为 1 并且只有一个字符具有该频率,则该字符串有效,因为可以简单地删除该字符
    • 如果最小频率比最大频率小 1,并且只有一个字符具有最大频率,则字符串有效,因为可以删除此字符。
  3. 在任何其他情况下,字符串将无效。


private static boolean isValid(String s) {
    TreeMap<Long, Long> frequencyCounts =
            s.chars()
             .boxed()
             // Frequency map
             .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
             .values()
             .stream()
             // Frequency of frequencies map
             .collect(Collectors.groupingBy
                                 (Function.identity(),
                                  TreeMap::new,
                                  Collectors.counting()));

    if (frequencyCounts.size() == 1) {
        return true;
    }

    if (frequencyCounts.size() == 2) {
        Iterator<Map.Entry<Long, Long>> iter = frequencyCounts.entrySet().iterator();
        Map.Entry<Long, Long> minEntry = iter.next();
        long minFrequency = minEntry.getKey();
        long numMinFrequency = minEntry.getValue();

        if (minFrequency == 1L && numMinFrequency == 1L) {
            return true;
        }

        Map.Entry<Long, Long> maxEntry = iter.next();
        long maxFrequency = maxEntry.getKey();
        long numMaxFrequency = maxEntry.getValue();
        if (numMaxFrequency == 1L && maxFrequency == minFrequency + 1L) {
            return true;
        }
    }

    return false;
}

编辑:
为了回答 cmets 中的问题,频率图和“频率的频率”图也可以用 Java 7 的语法构造,尽管它可能不那么优雅:

Map<Character, Long> frequencies = new HashMap<>();
for (int i = 0; i < s.length(); ++i) {
    char c = s.charAt(i);
    if (frequencies.containsKey(c)) {
        frequencies.put(c, frequencies.get(c) + 1L);
    } else {
        frequencies.put(c, 1L);
    }
}

TreeMap<Long, Long> frequencyCounts = new TreeMap<>();
for (Long freq : frequencies.values()) {
    if (frequencyCounts.containsKey(freq)) {
        frequencyCounts.put(freq, frequencyCounts.get(freq) + 1L);
    } else {
        frequencyCounts.put(freq, 1L);
    }
}

【讨论】:

  • 第一行是我们正在加载frequencyCounts 地图的位置。 Java 7有什么办法可以做到吗?我仍然从 Java 8 开始,所以仍处于学习阶段。
  • @flash 它可以在 Java 7 中完成(请参阅我编辑的答案),尽管您的原始代码使用了仅在 Java 8 中引入的getOrDefault,所以我不太确定您为什么会这样做我想强加这个限制。
【解决方案2】:

以下代码可以正常工作。我在这里所做的是将每个字符的频率存储在一个数组中,然后将其转换为列表,因为我们将需要稍后的时间点。接下来我将列表转换为设置并从中删除零,因为列表中将存在与输入字符串中不存在的字符相对应的零。如果 set 仅在删除零后的元素上具有,则意味着所有元素具有相同的频率,因此 返回 true。如果 set 有两个以上的元素,则意味着我们无法通过在一个位置删除一个字符来使其成为有效字符串,因此 return false。现在如果 set 有两个值,我们从 set 中获取最小值和最大值。如果有一个字符具有一个频率,即第一个如果条件适用,我们可以使其有效。现在第二个条件是,如果 b/w max 和 min 的差为 1,并且 max 只有一个频率,那么我们可以从 max 中删除一个字符并使其有效。

static String isValid(String s) {

        Integer arr[] = new Integer[26];
        Arrays.fill(arr, 0);
        //fill the frequency of every character in array arr
        for (int i = 0; i < s.length(); i++) {
            arr[s.charAt(i) - 97]++;
        }
        //convert array to list of integer     
        List<Integer> arrList = Arrays.asList(arr);

        //convert list to set and remove zero bcos zero correspond to char that is not present
        HashSet<Integer> set = new HashSet<Integer>(arrList);
        set.remove(new Integer(0));
        int len = set.size();
        // if size==1 means all freq are same
        if (len == 1)
            return "YES";
        else if (len == 2) {
            List<Integer> list = new ArrayList<>(set);
            int x = list.get(0);
            int y = list.get(1);
            int max = (x > y) ? x : y;
            int min = (x < y) ? x : y;

             // if min elemnnt has value one and freuency one
            if (Collections.frequency(arrList, min) == 1 && min == 1) {
                return "YES";
            }
          //if max-min==1 and there are only one elemnt with value=max      
         else if (max - min == 1) {
                if ((Collections.frequency(arrList, max) == 1)) {
                    return "YES";
                } else {
                    return "NO";
                }
            } 
          // if no of element is more than
          else {
                return "NO";
            }

        } else
            return "NO";
    }

【讨论】:

    【解决方案3】:

    java 8

    import java.util.*;
    public class MyClass {
        public static void main(String args[]) {
            Scanner scan = new Scanner(System.in);
            System.out.println(isValid(scan.next()));
    
        }
    
        private static String isValid(String s) {
            if (s == null || s.equals("")) {
              return "NO";
            }
    
            // frequencies ( hashmap) character : frequency 
            // contains frequency of each character of given string input
            Map<Character, Integer> frequencies = new HashMap<>();
            for (char ch : s.toLowerCase().toCharArray())
              frequencies.put(ch, frequencies.getOrDefault(ch, 0) + 1);
    

    .................................................. ..................................................... ..................................................... .....

            // freqTypesCount ( hashmap) 
            // frequency_type : number_of_chars_having this frequency_type 
            Map<Integer, Integer> freqTypesCount = new HashMap<>();
            for (int ch : frequencies.values())
              freqTypesCount.put(ch, freqTypesCount.getOrDefault(ch, 0) + 1);
    
    
            if( freqTypesCount.size() == 1){
                // it means all the chars of string occurs same number of time
                return "YES";
            }
            else if( freqTypesCount.size() > 2){
                // aaabbbbccdd
                // a : 3 b: 4 c:2 d:2 --> {3:1, 4:1, 2:2}
                // we can't make this string a valid string just by deleting single char
                return "NO";
            }
            else{
                int valid_freq = Collections.max(freqTypesCount.entrySet(), Map.Entry.comparingByValue()).getKey(); 
                int deleted = 0;
    
                for (Map.Entry<Character, Integer> entry : frequencies.entrySet())
                { 
                    int thisCharCount = entry.getValue();
    
                    if(thisCharCount != valid_freq){
    
                        if(deleted == 0){
                            if(thisCharCount - 1 == valid_freq || thisCharCount - 1 == 0){
                                deleted += 1;
                            }
                            else{
                                return "NO";
                            }
                        }
                        else{
                             return "NO";
                        }
                    }
                }
    
                return "YES" ;
            }
        }
    }
    

    .................................................. ..................................................... ..................................................... .....

    蟒蛇3

    from collections import Counter
    
    inp_string = input()
    
    def isValidStr( string):
        char_counter_dict = Counter( string)
        count_type_counter_dict = Counter(char_counter_dict.values())
    
        if len(count_type_counter_dict) == 1:
            return "YES"
        elif len(count_type_counter_dict) > 2:
            return "NO"
        else:
            valid_freq = count_type_counter_dict.most_common()[0][0]
    
            deleted = 0
    
            for char,count in char_counter_dict.items():
    
                if count != valid_freq:
    
                    if deleted == 0:
                        if count - 1 == valid_freq or count - 1 == 0:
                            deleted += 1
    
                        else:
                            return "NO"
    
                    else:
                        return "NO"
    
    
            return "YES"
    
    print(isValidStr(inp_string))
    

    【讨论】:

      最近更新 更多