My question is:
How do you check if a given string is the anagram of a palindrome?
I found some solutions in Python on the internet, but I'm not sure how can I check this yet. I was thinking about converting the strig to a char [], and then get the HashCode for every character, but I'm stuck.
If you're not interested in the palindrome or anagram being a real word then I think you can reframe the problem as check if a given string has no more than one character that appears an uneven number of times. This is on the basis that only the middle character can possibly occur an odd number of times. As long as that is satisfied then you can form a palindrome from the string.
To do that you can use Linq. Something like this perhaps:
private static bool IsPalindromeAnagram(string test)
{
var charCount = test.GroupBy(c => c, (c, i) => new
{
character = c,
count = i.Count()
});
return charCount.Count(c => c.count % 2 == 1) <= 1;
}
Saved char in a dictionary as key, then check if more than one key is odd. this way also have all unique char ready to make anagram.
var length = s.Length;
if (length == 0) return false;
var dic = new Dictionary<char, int>();
for (var i = 0; i < length; i++)
{
if (dic.ContainsKey(s[i]))
{
dic[s[i]]++;
continue;
}
dic.Add(s[i], 1);
}
int odd = 0;
foreach (var pv in dic)
{
if (odd > 1) return false;
if (pv.Value % 2 == 0)
{
continue;
}
odd++;
}
Related
I have a method who checks if it is a palindrome or not
public bool IsPalindrome(PalindromeModel model)
{
// First, check whether input string is null or whitespace.
// If yes, then return false.
if (string.IsNullOrWhiteSpace(model.Value))
return false;
var inputDict = new Dictionary<char, int>();
// Big/small letter is not important
var lowerInputStr = model.Value.ToLower();
// Fill input dictionary
// If hit a space, then skip it
for (var i = 0; i < lowerInputStr.Length; i++)
{
if (lowerInputStr[i] != ' ')
{
if (inputDict.ContainsKey(lowerInputStr[i]))
inputDict[lowerInputStr[i]] += 1;
else
inputDict.Add(lowerInputStr[i], 1);
}
}
var countOdds = 0;
foreach (var elem in inputDict)
{
if (elem.Value % 2 != 0)
countOdds++;
}
return countOdds <= 1;
}
So it works with this words: dood, A Santa Lived As a Devil At NASA
But for more complex palindromes like Mr. Owl Ate My Metal Worm it returns false, but it should be true, how can I achieve this?
Remove the spaces and the punctuations before the first loop
var lowerInputStr = new string(model.Value
.ToCharArray()
.Where(c => !char.IsPunctuation(c)).ToArray())
.ToLower()
.Replace(" ", "");
That solution looks overly complex. I'd just walk in from both edges, skipping over any characters you don't define as being in scope for comparison. In this implementation, I only consider letters while ignoring case. Note that the solution doesn't allocate any additional memory (as for example string.Replace() or string.ToLower() do internally) and runs worst case input (it is a palendrome) in O(N).
bool IsPalendrome(string input)
{
var left = 0;
var right = input.Length - 1;
while (left < right)
{
left = SkipNonLetters(input, left, 1);
right = SkipNonLetters(input, right, -1);
if (char.ToUpperInvariant(input[left]) != char.ToUpperInvariant(input[right]))
return false;
left++;
right--;
}
return true;
}
int SkipNonLetters(string input, int startAt, int direction)
{
while (startAt >= 0 && startAt < input.Length && !char.IsLetter(input[startAt]))
startAt += direction;
return startAt;
}
Examples:
Console.WriteLine(IsPalendrome("dood"));
Console.WriteLine(IsPalendrome("A Santa Lived As a Devil At NASA"));
Console.WriteLine(IsPalendrome("Mr. Owl Ate My Metal Worm"));
Output:
True
True
True
To expand on what Muhammad Sulaiman said, after you have the string cleaned up, the rest of the method can be a lot simpler
var lowerInputStr = new string(input.ToCharArray()
.Where(c => !char.IsPunctuation(c))
.ToArray())
.ToLower()
.Replace(" ", "");
return lowerInputStr.Substring(lowerInputStr.Length / 2) == (new String(lowerInputStr.Reverse().ToArray()))
.Substring(lowerInputStr.Length / 2);
I have a word "angoora" here 'a' and 'o' occurs 2 time if user input is 2 then output should be "ngr" function should remove a and o because it occur 2 times in a string. if user enter 3 then output should be "angoora" because no character occur 3 times.
I am doing this but I think its not a right way because its not leading me towards my goal, any help would be highly appreciated.
public static SortedDictionary<char, int> Count(string stringToCount)
{
SortedDictionary<char, int> characterCount = new SortedDictionary<char, int>();
foreach (var character in stringToCount)
{
int counter = 0;
characterCount.TryGetValue(character, out counter);
characterCount[character] = counter + 1;
}
return characterCount;
}
You can use LINQs GroupBy to find the number of times each character occurs. Then remove the ones that occur the number of times you want. Something like this
public static string RemoveCharactersThatOccurNumberOfTimes(string s, int numberOfOccurances)
{
var charactersToBeRemoved = s.GroupBy(c => c).Where(g => g.Count() == numberOfOccurances).Select(g => g.Key);
return String.Join("", s.Where(c => !charactersToBeRemoved.Contains(c)));
}
You Can use this Function
static string Fix(string item, int count)
{
var chars = item.ToList().GroupBy(g => g).Select(s => new { Ch = s.Key.ToString(), Count = s.Count() }).Where(w => w.Count < count).ToList();
var characters = string.Join("", item.ToList().Select(s => s.ToString()).Where(wi => chars.Any(a => a.Ch == wi)).ToList());
return characters;
}
Your characterCount SortedDictionary is empty.
Currently you are doing:
public static SortedDictionary<char, int> Count(string stringToCount)
{
// Create a new empty SortedDictionary
SortedDictionary<char, int> characterCount = new SortedDictionary<char, int>();
// Loop through each character in stringToCount and see if SortedDictionary contains a key equal to this character (it doesn't as dictionary is empty).
foreach (var character in stringToCount)
{
int counter = 0;
characterCount.TryGetValue(character, out counter);
characterCount[character] = counter +1;
}
return characterCount;
}
Surely you want something like this:
public static SortedDictionary<char, int> Count(string stringToCount)
{
// Create a new empty SortedDictionary (use var keyword if defining variables)
var characterCount = new SortedDictionary<char, int>();
// Loop through each character and add to dictionary
foreach (var character in stringToCount)
{
// If character already in SortedDictionary.
if (characterCount.TryGetValue(character, out int count))
{
// Increment count value.
characterCount[character] = count + 1;
// Above line can also be: ++characterCount[character];
}
// Else, character not already in dictionary.
else
{
// Add character in dictionary and set count to 1.
characterCount.Add(character, 1);
}
}
return characterCount;
}
public static string foobar(string given, int number)
{
string result = given;
foreach (char c in result.Distinct())
{
if (given.Count(ch => c == ch) >= number) result= result.Replace(c.ToString(),"");
}
return result;
}
Distinct() will give you only unique characters.
Then you Count() the occurance of each unique character and remove if it is greater or equal the given number.
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I have a string a = "aabbbffdshhh". I want to write a program which will give me output of "a2b3f2d1s1h3". I want to return each letter in the alphabet present and it's count.
The code I am currently using is:
int cnta;int cntb; int cntf; int cnth;
for (int i=0;i<a.lenghth;i++)
{
if(a[i]=='a')
{
cnta++;
}
if(a[i]=='b')
{
cntb++;
}
if(a[i]=='h')
{
cnth++;
}
}
It is giving me the output but this logic not good. What other algorithms or approaches could I use?
This should give you all of the data that you need for your results.
You should be able to append them into a string (using a StringBuilder) if you need the results in that format.
var results = s.GroupBy(c => c)
.Select(group => new
{
Letter = group.Key,
Count = group.Count()
});
One idea is to have a List<Tuple<char,int>> where you pre-populate with each char and 0 for it.
Increment the value of each character when encountered.
for (int i=0;i<a.lenghth;i++)
{
myList.Single(t => t.Item1 == a[i]).Item2++;
}
in general terms:
sort characters to obtain a sorted list with 1 instance of each char
create a list of counters the same size as the sorted list (each counter starts at 0)
loop over each char in the string incrementing the corosponding counters
loop over the sorted list constructing the result from the sorted list and counters.
var input = "aabbbffdshhh";
var characters = input.ToArray();
StringBuilder sb = new StringBuilder();
characters.ToList().ForEach(c=>{if(!sb.ToString().Contains(c)){sb.Append(c); sb.Append(characters.ToList().Count(cc=>cc == c));}});
//sb.ToString().Dump(); //output is a2b3f2d1s1h3
Done in LinqPad
Use a dictionary of type Dictionary. On the first occurrence add to the dictionary, on every subsequent increment.
This way you can use whatever characters you want (and control how to treat case) rather than just handling the 26
Assuming you're doing a slight variation of Run-length Encoding, this will encode your string. My comment went unanswered so I'm posing this as a guess. I'll leave the decoding as an exercise to you (or just check out rosettacode to see the implementation).
var a = "aabbbffdshhh";
var rle = new StringBuilder();
var last = a[0];
var count = 1;
for (int i = 1; i < a.Length; i++)
{
if (a[i] != last)
{
rle.AppendFormat("{0}{1}", last, count);
last = a[i];
count = 0;
}
count++;
}
rle.AppendFormat("{0}{1}", last, count);
Assert.AreEqual("a2b3f2d1s1h3", rle.ToString());
Can be done with 1 line of super readable code (sarcasm) :-) I have added an orderby even though this wasn't requested, you can remove if needed.
string a = "aaaadjkhsdfkjsdjkfhsdkjff";
var res = a.GroupBy(c => c).OrderBy(g => g.Key).Aggregate("", (p, g) => p += g.Key + g.Count().ToString());
or if you are one of those who think string concatenation is too inefficient
var res2 = a.GroupBy(c => c).OrderBy(g => g.Key).Aggregate(new StringBuilder(), (p, g) => p.Append(g.Key + g.Count().ToString())).ToString();;
in C# you could do:
Dictionary<char, int> d = new Dictionary<char, int>();
foreach(char c in a){
if(d.ContainsKey(c)){
d[c] = d[c] + 1;
} else {
d[c] = 1;
}
}
StringBuilder sb = new StringBuilder();
foreach(KeyValuePair p in d){
sb += p.Key.ToString() + p.Value.Tostring();
}
return sb.ToString();
Try this:
string a = "aaabbbasdlfjasldfkjalsdkfjaewoasdfj";
//store character counts in a dictionary
Dictionary<char, int> charCounts = new Dictionary<char, int>();
//iterate through string and place counts in dictionary
for (int i = 0; i < a.Length; i++)
{
if (!charCounts.Keys.Contains(a[i]))
{
charCounts[a[i]] = 1;
}
else
{
charCounts[a[i]] += 1;
}
}
//output sorted list
foreach (char letter in charCounts.Keys.OrderBy(x => x))
{
Console.Write(string.Format("{0}{1}", letter, charCounts[letter]));
}
this code should work in cpp
int* count = new int[26];
for (int i = 0; i < a.length; i++)
count[a[i] - 'a']++;
in c# you will need to play around a little so you well look at a char as a number.
I'm trying to figure out how to display the repeated letter in a string. For example if the entered string was "red house" it would show that the letter "e" was repeated, then it would be displayed in the label I created. This is a basic program, Here is what I've written thus far. Any help is appreciated.
private void button1_Click(object sender, EventArgs e)
{
string enteredWord = textBox1.Text;
char letter;
for (int index = 0; index < enteredWord.Length; index++)
{
letter = enteredWord[index];
if (letter == enteredWord[index])
{
label1.Text = (letter.ToString());
}
else
{ return;
}
You could also use Linq for that:
var query = from l in enteredWord
group l by l into g
where g.Count() > 1
select new { letter = g.Key, count = g.Count() };
foreach (var item in query)
{
label1.Text += item.letter + " ";
}
This should do what you're looking for:
public static Dictionary<char, int> Count(string input)
{
Dictionary<char, int> d = new Dictionary<char, int>();
foreach (char c in input)
{
if (d.Keys.Contains(c))
d[c]++;
else
d.Add(c, 1);
}
return d;
}
static void Main(string[] args)
{
Dictionary<char, int> d = Count("Red House");
foreach (char c in d.Keys)
{
Console.WriteLine("{0}: {1}", c, d[c]);
}
Console.ReadKey();
}
Could build a HashSet and check each letter. I'm sure there's a more efficient way, but this should work: (untested)
string enteredWord = textBox1.Text;
HashSet<char> letters = new HashSet<char>();
foreach(char c in enteredWord)
{
if (letters.Contains(c))
label1.Text += c.ToString();
else
letters.Add(c);
}
EDIT: I suppose this will print out duplicates of the letters if they appear 3 or more times, but you get the idea.
I would suggest using a List and add the value if you have not encountered it, and update the textbox if you have already encountered it. For a future FYI, you could use a Dictionary if you need to know the exact counts, also.
List<char> charactersThatHaveOccurred = new List<char>();
string enteredWord = textBox1.Text;
foreach(var character in enteredWord)
{
if(charactersThatHaveOccurred.Contains(character ))
label1.Text += character ;
else
charactersThatHaveOccurred.Add(character );
}
The first thing that comes to mind is:
List<char> repeats = enteredWord.Where(c1 => enteredWord.Count(c2 => c1 == c2) > 1).Distinct().ToList();
That will return a List<char> of all the repeated characters. You can grab the first one, or whatever you want.
It may not be optimal in terms of speed, but it's simple.
See other answers for better ways to solve this problem, but I'm trying to see what you were trying to do. (Note, the code below is very inefficient, using a HashSet of already seen characters would be my solution at it.)
Perhaps you're missing an inner for loop? Currently you assign something (enteredword[index]) to letter, and then immediately compare them. So you're comparing each letter to itself.
something like
for (int index = 0; index < enteredWord.Length; index++)
{
letter = enteredWord[index];
for (int index2 = 0; index < enteredWord.Length; index++)
{
if (index != index2 && letter == enteredWord[index2])
{
label1.Text = (letter.ToString());
return;
}
}
}
string s = "red house";
foreach (char c in s)
{
if (s.IndexOf(c) != s.LastIndexOf(c))
{
label1.Text += c.ToString();
}
s.Replace(c.ToString(), string.Empty);
}
For example, a user entered "I love this post!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
the consecutive duplicate exclamation mark "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" should be detected.
The following regular expression would detect repeating chars. You could up the number or limit this to specific characters to make it more robust.
int threshold = 3;
string stringToMatch = "thisstringrepeatsss";
string pattern = "(\\d)\\" + threshold + " + ";
Regex r = new Regex(pattern);
Match m = r.Match(stringToMatch);
while(m.Success)
{
Console.WriteLine("character passes threshold " + m.ToString());
m = m.NextMatch();
}
Here's and example of a function that searches for a sequence of consecutive chars of a specified length and also ignores white space characters:
public static bool HasConsecutiveChars(string source, int sequenceLength)
{
if (string.IsNullOrEmpty(source))
return false;
if (source.Length == 1)
return false;
int charCount = 1;
for (int i = 0; i < source.Length - 1; i++)
{
char c = source[i];
if (Char.IsWhiteSpace(c))
continue;
if (c == source[i+1])
{
charCount++;
if (charCount >= sequenceLength)
return true;
}
else
charCount = 1;
}
return false;
}
Edit fixed range bug :/
Can be done in O(n) easily: for each character, if the previous character is the same as the current, increment a temporary count. If it's different, reset your temporary count. At each step, update your global if needed.
For abbccc you get:
a => temp = 1, global = 1
b => temp = 1, global = 1
b => temp = 2, global = 2
c => temp = 1, global = 2
c => temp = 2, global = 2
c => temp = 3, global = 3
=> c appears three times. Extend it to get the position, then you should be able to print the "ccc" substring.
You can extend this to give you the starting position fairly easily, I'll leave that to you.
Here is a quick solution I crafted with some extra duplicates thrown in for good measure. As others pointed out in the comments, some duplicates are going to be completely legitimate, so you may want to narrow your criteria to punctuation instead of mere characters.
string input = "I loove this post!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!aa";
int index = -1;
int count =1;
List<string> dupes = new List<string>();
for (int i = 0; i < input.Length-1; i++)
{
if (input[i] == input[i + 1])
{
if (index == -1)
index = i;
count++;
}
else if (index > -1)
{
dupes.Add(input.Substring(index, count));
index = -1;
count = 1;
}
}
if (index > -1)
{
dupes.Add(input.Substring(index, count));
}
The better way i my opinion is create a array, each element in array is responsible for one character pair on string next to each other, eg first aa, bb, cc, dd. This array construct with 0 on each element.
Solve of this problem is a for on this string and update array values.
You can next analyze this array for what you want.
Example: For string: bbaaaccccdab, your result array would be { 2, 1, 3 }, because 'aa' can find 2 times, 'bb' can find one time (at start of string), 'cc' can find three times.
Why 'cc' three times? Because 'cc'cc & c'cc'c & cc'cc'.
Use LINQ! (For everything, not just this)
string test = "aabb";
return test.Where((item, index) => index > 0 && item.Equals(test.ElementAt(index)));
// returns "abb", where each of these items has the previous letter before it
OR
string test = "aabb";
return test.Where((item, index) => index > 0 && item.Equals(test.ElementAt(index))).Any();
// returns true