Sunday, February 10, 2019

Sherlock and the Valid String - Hacker Rank Solution

Sherlock considers a string to be valid if all characters of the string appear the same number of times. It is also valid if he can remove just  character at  index in the string, and the remaining characters will occur the same number of times.
Given a string , determine if it is valid. If so, return YES, otherwise return NO.
For example, if , it is a valid string because frequencies are . So is  because we can remove one  and have  of each character in the remaining string. If  however, the string is not valid as we can only remove  occurrence of . That would leave character frequencies of .
Function Description
Complete the isValid function in the editor below. It should return either the string YES or the string NO.
isValid has the following parameter(s):
  • s: a string
Input Format
A single string .
Constraints
  • Each character 
Output Format
Print YES if string  is valid, otherwise, print NO.
Sample Input 0
aabbcd
Sample Output 0
NO
Explanation 0
Given , we would need to remove two characters, both c and d  aabb or a and b  abcd, to make it valid. We are limited to removing only one character, so  is invalid.
Sample Input 1
aabbccddeefghi
Sample Output 1
NO
Explanation 1
Frequency counts for the letters are as follows:
{'a': 2, 'b': 2, 'c': 2, 'd': 2, 'e': 2, 'f': 1, 'g': 1, 'h': 1, 'i': 1}
There are two ways to make the valid string:
  • Remove  characters with a frequency of .
  • Remove  characters of frequency .
Neither of these is an option.
Sample Input 2
abcdefghhgfedecba
Sample Output 2
YES
Explanation 2
All characters occur twice except for  which occurs  times. We can delete one instance of  to have a valid string.

Sherlock and the Valid String - Hacker Rank Solution

An overview of the solution is to get a count of all distinct characters in the string and then test for valid conditions. Three cases exist that are valid strings:
  1. If all have the same frequency
  2. If only  character has a frequency that is  greater than all others
  3. If all have the same frequency except  element which has a frequency of 

Problem Setter's code:

C++

#include <bits/stdc++.h>
using namespace std;

int main() {
  set<int> myset;
  string s;
  cin >> s;
  string ans = "NO";

  // cnt[i] stores frequency of character i+'a'
  int cnt[26] = {}, n = s.length();

  for (int i = 0; i < n; i++) {
    // increasing frequency
    cnt[s[i] - 'a']++;
  }

  // for i>=0, it means we are removing character i+'a', if possible
  // case i=-1 is for checking if string is already valid

  for (int i = -1; i < 26; i++) {
    // if character i+'a' is not present in string continue
    if (i >= 0 and cnt[i] == 0)
      continue;

    // reduce frequency
    if (i >= 0)
      cnt[i]--;

    // if we insert all positive frequencies into a set, it should contain
    // only 1 element if string is now valid
    set<int> myset;

    // insert remaining positive frequencies into set
    for (int j = 0; j < 26; j++) {
      if (cnt[j])
        myset.insert(cnt[j]);
    }

    // if set size is 1, string is now valid
    if (myset.size() == 1)
      ans = "YES";

    // increase the frequency back again
    if (i >= 0)
      cnt[i]++;
  }
  cout << ans << endl;
  return 0;
}
Problem Tester's code:
from collections import Counter

def isValid(s):
    cnt = Counter(s)
    if len(set(cnt.values())) == 1:
        return "YES"
    elif len(set(cnt.values())) > 2:
        return "NO"
    else:
        m1 = max(cnt.values())
        m2 = min(cnt.values())
        if cnt.values().count(m2) == 1:
            return "YES"
        if cnt.values().count(m1) > 1 or m1 - m2 > 1:
            return "NO"
        return "YES"

s = raw_input().strip()
result = isValid(s)
print(result)

Another Solution (Editorial)

from collections import Counter

def check(cnt):
    ls = cnt.values()
    try:
        ls.remove(0)
    except:
        pass
    if len(set(ls)) == 1:
        return True
    else:
        return False

def isValid(s):
    cnt = Counter(s)
    if check(cnt):
        return "YES"
    for i in cnt.keys():
        cnt[i] -= 1
        if check(cnt):
            return "YES"
        else:
            cnt[i] += 1
    return "NO"

s = raw_input().strip()
result = isValid(s)
print(result)

2 comments:

  1. in c++ solution we could use a break statement inside if case of making ans = 'yes'. it will reduce execution time

    ReplyDelete
  2. there is an error .. raw_input() is not defined

    ReplyDelete

Powered by Blogger.