Sherlock和有效字符串,在5个测试用例中给我错误的结果

时间:2018-07-28 07:37:28

标签: java string

我正在尝试从hackerrank运行程序。这是问题:

如果字符串的所有字符出现相同的次数,Sherlock认为该字符串有效。如果他只能在字符串的 one 索引中删除一个字符,并且其余字符出现相同的次数,则也是有效的。给定一个字符串,确定它是否有效。

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

这是链接: https://www.hackerrank.com/challenges/sherlock-and-valid-string/problem?h_l=interview&playlist_slugs%5B%5D=interview-preparation-kit&playlist_slugs%5B%5D=strings

失败的5个测试用例之一是: aaaabbcc应该给出错误的信息,但是它给了我真实的信息。 aabbc应该给真,但是给我错。

但是不知何故我的5个测试用例就出错了: 这是下面的程序。

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

public class SherlokValidString
{

    boolean is_valid(String s)
    {
        int count=0;
        HashMap<Character, Integer> map = new HashMap<>();
        char[] str_arr= s.toCharArray();
        for(char c:str_arr)
        {
            if(map.containsKey(c))
            {
                map.put(c, map.get(c)+1);
            }
            else
            {
                map.put(c,1);
            }
        }
        if (map.size()==1)
        {
            return true;
        }
        else {

            List ll=new ArrayList<>(map.values());
            System.out.println(ll);

            Collections.sort(ll);
            int first_element=(int)ll.get(0);

            for(int i=1;i<(ll.size()-1);i++)
            {
                //System.out.println((int)ll.get(i)+1);
                if (first_element==(int)ll.get(i+1))
                {
                    count=0;
                }
                else if(first_element!=(int)ll.get(i+1))
                {
                    count++;
                }
            }
            if(count<=1)
            {
                //System.out.println(count);
                return true;
            }
            else
            {
                return false;
            }
        }
    }

    public static void main(String[] args)
    {
        SherlokValidString svs = new SherlokValidString();
        System.out.println(svs.is_valid("abbccc"));

    }
}

它应该返回false,它使我成真。 请帮忙。谢谢。

8 个答案:

答案 0 :(得分:1)

使用Java 8,可以做得非常出色:

public static boolean sherlockStr(String s) {

    // First, we're going to walk over the characters and count how many
    // times each character occurs
    Map<Character, Long> charOccurs = s.chars()
        .mapToObj(t -> (char) t)
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

    // Then we're going to map each amount of characters found to its count,
    // e.g. in the string "aabbcc" each character occurs twice → [2, 2, 2].
    // That will yield a map: [2=3]
    Map<Long, Long> counts = charOccurs.entrySet().stream()
        .map(Map.Entry::getValue)
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

    switch (counts.size()) {
        // If all characters occur an equal number of times, then the map
        // contains just a single entry.
        case 1:
            return true;

        // If there are two different amounts, then the difference between
        // those two must be 1. Also, one of the numbers must occur exactly
        // once.
        case 2:
            Iterator<Long> it = counts.keySet().iterator();
            boolean diff = Math.abs(it.next() - it.next()) == 1;
            return (diff && (counts.values().stream()
                .anyMatch(i -> i == 1)));

        // If the map's size is 3 or more, there are differents of amounts of
        // characters.
        default:
            return false;
    }
}

简而言之:

public static boolean sherlockStr(String s) {
    Map<Long, Long> counts = s.chars()
        .mapToObj(t -> (char) t)
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
        .entrySet().stream()
        .map(Map.Entry::getValue)
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

    switch (counts.size()) {
        case 1:
            return true;
        case 2:
            Iterator<Long> it = counts.keySet().iterator();
            return (Math.abs(it.next() - it.next()) == 1 && (counts.values().stream()
                .anyMatch(i -> i == 1)));
        default:
            return false;
    }
}

答案 1 :(得分:0)

我发现您的逻辑中有以下失败:

  1. 最后一个循环的结束边界是错误的。从i == 1开始真的没关系(因为初始化first_element时隐式处理了第一项),但是结束边界必须为ll.size(),而不是ll.size()-1

  2. 决定count是否必须递增的条件太宽泛,并且应该更具限制性:仅使出现的频率与最低频率不同是不够的(包含在first_element中);还必须确保至少为1+first_element。而且,如果更高,则必须中断循环并返回false。

答案 2 :(得分:0)

尝试以下操作,查看评论:

boolean isValid(String s)
{
    HashMap<Character, Integer> map = new HashMap<>();
    char[] str_arr= s.toCharArray();
    for(char c:str_arr)
    {
        if(map.containsKey(c))
        {
            map.put(c, map.get(c)+1);
        }
        else
        {
            map.put(c,1);
        }
    }

    //define min max frequencies
    int min = (int) Math.pow(10, 5); int max = 0;
    for(int value : map.values()) {
        if (value < min ) {
            min = value;
        }
        if(value > max ) {
            max = value;
        }
    }

    if(min == max) { return true;} //all frequencies equal
    if( (max - min) > 1) {return false;} //removing one character can not make the equal

    //for other cases make sure that only one frequency is different
    int countBiggerThanMin = 0;
    for(int value : map.values()) {
        if(value > min ) {
            countBiggerThanMin++;
        }
    }

    if((countBiggerThanMin == 1) || //only one bigger than min
            (countBiggerThanMin == (map.size() - 1))) { //min is samller than all others
        return true;
    }
    return false;
}

通过使用Java 8 Stream,它变得更加简洁:

boolean isValidForJava8(String s) {

    Stream<String> stream = Stream.of(s.split(""));

    Map<String, Long> map = stream.collect(
            Collectors.groupingBy( Function.identity(), Collectors.counting() ));

    Long min = map.values().stream().min(Long::compareTo).get();
    Long max = map.values().stream().max(Long::compareTo).get();

    if(min == max) { return true;} //all frequencies equal
    if( (max - min) > 1) {return false;} //removing one character can not make the equal

    //for other cases make sure that only one frequency is different
    int countBiggerThanMin = map.values().stream().mapToInt(v -> (v > min) ? 1 : 0).sum();

    if((countBiggerThanMin == 1) || //only one bigger than min
            (countBiggerThanMin == (map.size() - 1))) { //min is samller than all others
        return true;
    }
    return false;
}

答案 3 :(得分:0)

这是一个完美的解决方案:

{
if ((s.size() == 1) || (s.size() == 2))
    return "YES";
std::map <char, int> hashValues;
for (char &c: s)
{
    if (hashValues.count(c) != 0)
        hashValues[c]++;
    else
        hashValues.insert(std::pair <char, int> (c,1));
}
int highest = 0;
int lowest = 100000;
for (map<char,int>::iterator it = hashValues.begin(); it != hashValues.end(); it++)
{
    if (it->second < lowest)
        lowest = it->second;
    if (it->second > highest)
        highest = it->second;
}
int countMin = 0;
int countMax = 0;
for (map<char,int>::iterator it = hashValues.begin(); it != hashValues.end(); it++)
{
    if (it->second == highest)
        countMax++;
    if (it->second == lowest)
        countMin++;
}
if ((highest - lowest) == 0) {return "YES";};
if (((highest - lowest) == 1) && (countMax == 1))
    return "YES";
if (((highest - lowest) == 2))
    return "NO";
if ((lowest == 1) && (countMin == 1))
    return "YES";
return "NO";

}

答案 4 :(得分:0)

科特琳(Kotlin)带来一点优雅=)

    if (s.length == 1) return "YES"

    val freq = s.groupingBy { it }.eachCount()
    val max:Int = freq.maxBy { it.value }!!.value
    val maxCount = freq.count { it.value == max }

    val min = freq.minBy { it.value }!!.value
    val minCount = freq.count { it.value == min }

    val freqOfFreq = freq.map { it.value }.groupingBy { it }.eachCount()
    return when {
        freqOfFreq.size > 2 -> return "NO"
        freqOfFreq.size == 1 -> return "YES"
        minCount == 1 -> return "YES"
        max - maxCount == min -> return "YES"
        else -> "NO"
    }

答案 5 :(得分:0)

静态列表myCharList = new ArrayList <>();

static int isValidStringProcessor(String s) {
    int returnStatus=-2;

    List<Character> chars = s.chars().mapToObj(e -> (char)e).collect(Collectors.toList()); 
    List<Integer> myList = new ArrayList<>();

    Map<Character, Long> frequencyMap =
            chars.stream().collect(Collectors.groupingBy(Function.identity(), 
                                                    Collectors.counting()));

    for (Map.Entry<Character, Long> entry : frequencyMap.entrySet()) {
        myList.add(entry.getValue().intValue());
        myCharList.add(entry.getKey());
    }    

    int min = Collections.min(myList);
    int max = Collections.max(myList);   
    int minFrequency = Collections.frequency(myList, min);
    int maxFrequency = Collections.frequency(myList, max);

    if ((max==min)) {
        returnStatus=-1;
    } else if ((minFrequency==1 && maxFrequency==(myList.size()-1))  && (max-min==1)) {
        returnStatus=myList.indexOf(min);
    } else if ((minFrequency==(myList.size()-1) && maxFrequency==1) && (max-min==1)) {
        returnStatus=myList.indexOf(max);
    }

    return returnStatus;
}
// Complete the isValid function below.
static String isValid(String s) {
   String result ="NO";
    int validIdenfitier = isValidStringProcessor(s);
    if (validIdenfitier == -1) {
        result="YES"; 
    } else if (validIdenfitier >= 0) {
        Character ch = myCharList.get(validIdenfitier);
        String newString = s.replaceFirst(ch+"", "");
        if (isValidStringProcessor(newString) == -1)
            result="YES";
    }
    return result;

}

答案 6 :(得分:0)

尝试此方法可以通过所有测试用例,类似于您的方法。 :)

static String isValid(String s) {
    char c[]=s.toCharArray();

    HashMap<Character,Integer> map=new HashMap<Character,Integer>();
    for(char ch: c){ 
        if(!map.containsKey(ch)){
            map.put(ch,1);
        }
        else
            map.put(ch,map.get(ch)+1);
    }
    
    Set<Integer> st = new HashSet<>();
    for(int freq : map.values())
    {
        st.add(freq);
    }

    if(st.size() > 2)//More than 2 frequencies
        System.out.println("NO");
    else if(st.size() == 1)
        return "YES";

    else{
        int f1 = 0;
        int f2 = 0;
        int f1Count = 0;
        int f2Count = 0;
        int i = 0;
        for(int n : st)
        {
            if(i == 0) f1 = n;
            else f2 = n;
            i++;
        }
        
        for(int freq : map.values())
        {
            if(freq == f1) f1Count++;
            if(freq == f2) f2Count++;
        }
        
        
        
        if((f1 == 1 && f1Count == 1 ) || (f2 == 1 && f2Count == 1 ))
            return "YES";
        else if ((Math.abs(f1 - f2)  == 1) && (f1Count == 1 || f2Count == 1))
            return "YES";
        else
           return "NO";

}
 return "NO";

}

答案 7 :(得分:0)

    public String isValid(String s) {
        HashMap<Character, Integer> trackFrequency = new HashMap<>();
            for (int i = 0; i < s.length(); i++) {
                Character c = s.charAt(i);
                if (trackFrequency.containsKey(c)) {
                    int count = trackFrequency.getOrDefault(c, 0);
                    count = count + 1;
                    trackFrequency.put(c, count);
                } else {
                    trackFrequency.put(c, 1);
                }
            }
            int sample = trackFrequency.get(s.charAt(0));
            int unEqualFrequency = 0;
            int unEqualValue = 0;
            for (Integer value : trackFrequency.values()) {
                if (sample != value) {
                    unEqualFrequency++;
                }
                if (unEqualFrequency == 1) {
                    unEqualValue = value;
                }
            }
            if (unEqualFrequency > 1) {
                return "NO";
            } else if (Math.abs(sample - unEqualValue) <= 1 || 
                 unEqualFrequency <= 1) {
                return "YES";
            } 
            return "NO";
        }
     
    
Here i am calculating the no of times the values are different in hashmap . There are three cases 
    if its  == 0 > its sherlock string
    if its >1 -> its not a Sherlock String 
    if its == 1 and the difference of the two values is ==1 -> its sherlock string