How to rearrange a string so no adjent letters are the same - c#

I am trying to rearrange a given string, so no two adjacent letters are the same.
For that I'm thinking to count every distinct letter's occurence, and then rearrange the string the characters occurence number
example:
Input: AABAABBC
Output: AAAABBBC
and after that spliting it in 2 different strings
AAAA BBBC
and then trying to get the final result.
My question is how do I rearrange the string without using Linq?
Here is my code so far:
private static string GetDistinctChars(string text)
{
string result = "";
foreach (char c in text)
{
if (!result.Contains(c))
{
result += c;
}
}
return result;
}
private static double GetCharOccurrence(string text, char charToCount)
{
int count = 0;
foreach (char c in text)
{
if (c == charToCount)
{
count++;
}
}
return count;
}

You can do it like that:
string example = "AABBAACDCAA";
var orderList = example.OrderBy(x => x).ToList();
List<string> letters = new List<string>();
string temp = string.Empty;
for(int i = 0; i < orderList.Count; i++)
{
temp += orderList[i];
if (i + 1 == orderList.Count)
{
letters.Add(temp);
break;
}
if(orderList[i] != orderList[i + 1])
{
letters.Add(temp);
temp = string.Empty;
}
}
string result = String.Join(" ", letters);
Console.WriteLine(result);
If you don't want to use Linq Order by method, you should implement sorting algorithm like this:
static char[] SortArray(char[] array)
{
int length = array.Length;
char temp = array[0];
for (int i = 0; i < length; i++)
{
for (int j = i + 1; j < length; j++)
{
if (array[i] > array[j])
{
temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
return array;
}
and use it in your program:
string example = "AABBAACDCAA";
var orderList = SortArray(example.ToCharArray());
List<string> letters = new List<string>();
string temp = string.Empty;
for(int i = 0; i < orderList.Length; i++)
{
temp += orderList[i];
if (i + 1 == orderList.Length)
{
letters.Add(temp);
break;
}
if(orderList[i] != orderList[i + 1])
{
letters.Add(temp);
temp = string.Empty;
}
}
string result = String.Join(" ", letters);
Console.WriteLine(result);
alternativly, if you don't want to use list anymore, you can operate only on strigns:
string example = "AABBAACDCAA";
var orderList = SortArray(example.ToCharArray());
string lettersString = string.Empty;
for (int i = 0; i < orderList.Length; i++)
{
lettersString += orderList[i];
if (i + 1 == orderList.Length)
break;
if (orderList[i] != orderList[i + 1])
lettersString += " ";
}
Console.WriteLine(lettersString);

You can find your problem on LeetCode, it's a problem #767.
My algorithm is
If we have too many of same characters, we can't solve the problem (e.g. "aaaaaabc")
If solution exists, we can sort characters aababc -> aaabbc and then take item by item from the beginning and from the center:
For instance:
aababc -> aaabbc (ordered by frequency: a appears 3 time, b - 2, c - 1)
then
aaabbc => ab
^ ^
take these
aaabbc => abab
^ ^
take these
aaabbc => ababac <- final answer
^ ^
take these
Code:
using System.Linq;
using System.Text;
...
public static string ReorganizeString(string s) {
int count = s.GroupBy(c => c).Max(g => g.Count());
// One of the item is too frequent, no solutions
if (count > (s.Length + 1) / 2)
return "";
string st = string.Concat(s
.GroupBy(c => c)
.OrderByDescending(g => g.Count())
.ThenBy(g => g.Key) // not required, just for aesthetic
.SelectMany(c => c));
StringBuilder sb = new StringBuilder(s.Length);
for (int i = 0; i < s.Length / 2; ++i) {
sb.Append(st[i]);
sb.Append(st[(st.Length + 1) / 2 + i]);
}
// Middle character
if (s.Length % 2 != 0)
sb.Append(st[st.Length / 2]);
return sb.ToString();
}
Demo:
string value = "AABAABBC";
Console.Write(ReorganizeString(value));
Output:
ABABABAC
Fiddle it yourself.
Edit: If StringBuilder (as well as System.Text) is really forbidden, we can use string, which, however, slows down the routine:
using System.Linq;
...
public static string ReorganizeString(string s) {
int count = s.GroupBy(c => c).Max(g => g.Count());
// One of the item is too frequent, no solutions
if (count > (s.Length + 1) / 2)
return "";
string st = string.Concat(s
.GroupBy(c => c)
.OrderByDescending(g => g.Count())
.ThenBy(g => g.Key) // not required, just for aesthetic
.SelectMany(c => c));
string result = "";
for (int i = 0; i < s.Length / 2; ++i) {
result += st[i];
result += st[(st.Length + 1) / 2 + i];
}
// Middle character
if (s.Length % 2 != 0)
result += st[st.Length / 2];
return result;
}

Related

Compare chars in two strings of different length in C#

In C#, Im trying to compare two strings and find out how many chars are different.
I Tried this:
static void Main(String[] args)
{
var strOne = "abcd";
var strTwo = "bcd";
var arrayOne = strOne.ToCharArray();
var arrayTwo = strTwo.ToCharArray();
var differentChars = arrayOne.Except(arrayTwo);
foreach (var character in differentChars)
Console.WriteLine(character); //Will print a
}
but there are problems with this:
if the strings contain same chars but on different positions within the string
it removes the duplicate occurences
If the strings would be the same length I would compare the chars one by one but if one is bigger than the other the positions are different
You may want to have a look at the Leventshtein Distance Algorithm.
As the article says
the Levenshtein distance between two words is the minimum number of
single-character edits (insertions, deletions or substitutions)
required to change one word into the other
You can find many reference implementations in the internet, like here or here.
public static int LevenshteinDistance(string s, string t)
{
int n = s.Length;
int m = t.Length;
int[,] d = new int[n + 1, m + 1];
if (n == 0)
{
return m;
}
if (m == 0)
{
return n;
}
for (int i = 0; i <= n; d[i, 0] = i++)
{
}
for (int j = 0; j <= m; d[0, j] = j++)
{
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
int cost = (t[j - 1] == s[i - 1]) ? 0 : 1;
d[i, j] = Math.Min(
Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1),
d[i - 1, j - 1] + cost);
}
}
return d[n, m];
}
}
How about this? Append two strings into one and group them, you will have the count of the chars, > 1 will give the repeatings and = 0 will give the unique ones.
var strOne = "abcd";
var strTwo = "bcd";
var arrayOne = strOne.Concat(strTwo).GroupBy(x => x).Select(x => new { Key = x.Key, Count = x.Count() });
foreach (var character in arrayOne) {
if (character.Count > 1)
{
Console.WriteLine(character.Key); // the repeating chars
}
}
If the same character appears twice in the same string,
var strOne = "abbcdd";
var strTwo = "cd";
var arrayTwo = strOne.Select(x => new { Key = x, IsExists = strTwo.Any(y => y == x) });
foreach (var character in arrayTwo) {
if (character.IsExists)
{
Console.WriteLine(character.Key);
}
}

C# merge lines of strings into groups of 3 at a time

I have a string like this (including newlines)
A2,
10.22,
-57,
A,
10.23,
-68,
A2,
10.24,
-60,
LB,
10.25,
-62,
I am trying to make this string to look like this:
A2,10.22,-57,
A,10.23,-68,
A2,10.24,-60,
LB,10.25,-62,
I need to join string in every 3 line i have tried :
int numLines = a.Split('\n').Length;
for (int i = 0; i < numLines; i += 3)
{
richTextBox1.Text = a.Replace("\n", "");
}
But it is not working for me. Please help me out
You can also approach this with LINQ, by using the index overload of .Select to retain a running count of the line numbers, and then to group them into groups of 3 - I've used integer division to Floor the line index, 3 at a time, but there are likely other suitable ways.
var groups = values.Select((s, idx) => (Index: idx / 3, Value: s))
.GroupBy(x => x.Index);
Where each item in the groups above will be IEnumerable<(Index, Value)>.
You'll also need to be wary of newlines - these may be \r\n in Windows, not just the \n you've indicated.
Here's an example:
var a =
#"A2,
10.22,
-57,
A,
10.23,
-68,
A2,
10.24,
-60,
LB,
10.25,
-62,";
var values = a.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
var groups = values.Select((s, idx) => (Index: idx / 3, Value: s))
.GroupBy(x => x.Index);
foreach (var grp in groups)
{
Console.WriteLine(string.Join("", grp.Select(x => x.Value)));
}
Since you've already got commas at the end of each string (including the last one), there's no need to add another separator.
Output:
A2,10.22,-57,
A,10.23,-68,
A2,10.24,-60,
LB,10.25,-62,
Why not use the array that the split gives you instead?
var newArr = a.Split('\n');
for (int i = 0; i < newArr.Length; i += 3)
{
richTextBox1.Text = newArr[i] + newArr[i + 1] + newArr[i + 2];
}
Just don't forget to check the length of the arrays so that you don't get a IndexOutOfRange Exception.
I'm assuming that the input is actually coming from a file here.
var file = //file path
var sb = new StringBuilder();
var lineNum = 1;
var output = string.Empty;
using (var reader = new StreamReader(file))
{
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
if (lineNum % 3 == 0)
{
output += sb.ToString() + "\n";
sb.Clear();
}
else
sb.Append(line);
lineNum++;
}
}
richTextBox1.Text = output;
Try this solution which is a combination of linq and for loop
var result = "";
var items = yourInputString.Split('\n');
for(var i=0; i<items.Count();i=i+3)
{
result += string.Join(",",items.Skip(i).Take(3))+"\n";
}
static void Main(string[] args)
{
var Lines = System.IO.File.ReadAllLines("input.txt");
var Result = new StringBuilder();
var SB = new StringBuilder();
for (var i = 0; i < Lines.Length; i++)
{
SB.Append(Lines[i]);
if ((i+1) % 3 == 0)
{
Result.Append($"{SB.ToString()}{Environment.NewLine}");
SB.Clear();
}
}
System.IO.File.WriteAllText("output.txt", Result.ToString());
}
Try to use Aggregate function
var outPutList = data.Replace("\r", string.Empty).Replace("\n", string.Empty).Split(",").Aggregate(new StringBuilder(""), (x, y) =>
{
if (double.TryParse(y, out double parsedValue))
x.Append(" " + parsedValue);
else
{
x.Append(Environment.NewLine);
x.Append(y.Trim());
}
return x;
});
richTextBox1.Text = outPutList.ToString();
Here is the output
try this works
private void button1_Click(object sender, EventArgs e)
{
//put your string in a textxbox with multiline property set to true
string[] s = textBox1.Text.Replace("\r", "").Replace("\n", "").Split(',');
string r = "";
for (int i = 0; i < s.Length; i++)
{
r = r + s[i] + ",";
if ((i + 1) % 3 == 0)
r = r + "+";
}
if (r.Substring(r.Length - 1, 1) == ",")
r = r.Substring(0, r.Length - 1);
if (r.Substring(r.Length - 1, 1) == "+")
r = r.Substring(0, r.Length - 1);
string[] finalArrayString = r.Trim().Split('+');
//just for show the result
textBox1.Text = "";
for (int i = 0; i < finalArrayString.Length; i++)
textBox1.Text = textBox1.Text + finalArrayString[i] + "\r\n";
}
hope it helps you

In place algorithm for string transformation

Given a string, move all digit elements to end of string. While moving elements, keep the relative order of all positioned elements same.
For example, if the given string is
a1b2c3d4e5f6g7h8i9j1k2l3m4
convert it to
abcdefghijklm1234567891234
in-place and in O(n) time complexity.
I got a different result
abcdefghijklm7481951326324
Also I failed for testing another string
aHR0cDovL3d3dy5nZWVrc2ZvcmdlZWtzLm9yZy9hbi1pbi1wbGFjZS1hbGdvcml0aG0tZm9yLXN0cmluZy10cmF
Code:
static string s = "a1b2c3d4e5f6g7h8i9j1k2l3m4";
static void Main(string[] args)
{
char[] input = s.ToCharArray();
string output = arrangeList(input);
Console.WriteLine(output);
Console.WriteLine("Another test");
s = "aHR0cDovL3d3dy5nZWVrc2ZvcmdlZWtzLm9yZy9hbi1pbi1wbGFjZS1hbGdvcml0aG0tZm9yLXN0cmluZy10cmF";
input = s.ToCharArray();
output = arrangeList(input);
Console.WriteLine(output);
Console.Read();
}
private static string arrangeList(char[] x)
{
for (int i = 1; i < x.Length - 1; i++)
{
int j = i + 1;
while (j < x.Length)
{
if ( (x[j] > '0' && x[j] < '9') && x[i] > '9')
{
swap(x, i, j); j++;
break;
}
if ( (x[i] > '0' && x[i] < '9') && x[j] > '9')
{
swap(x, i, j); j++;
break;
}
j++;
}
}
return new string(x);
}
private static void swap(char[] a, int i, int j)
{
char temp = a[i];
a[i] = a[j];
a[j] = temp;
}
With Linq
var input = "a1b2c3d4e5f6g7h8i9j1k2l3m4";
var output = String.Join("", input.GroupBy(c => char.IsDigit(c))
.OrderBy(x => x.Key) //Always 2 items to sort. Not O(N*logN)
.SelectMany(g => g));
You can build it in a character array pretty easily by working from the back to copy digits and from the front to copy letters. That is:
var input = "a1b2c3d4e5f6g7h8i9j1k2l3m4";
int ixLetter = 0;
int ixDigit = input.Length - 1;
int oxLetter = 0;
int oxDigit = input.Length - 1;
char[] output = new char[input.Length];
while (ixDigit >= 0)
{
if (char.IsDigit(input[ixDigit]))
{
output[oxDigit] = input[ixDigit];
--oxDigit;
}
if (!char.IsDigit(input[ixLetter]))
{
output[oxLetter] = input[ixLetter];
++oxLetter;
}
--ixDigit;
++ixLetter;
}
string result = new string(output);
This does two passes over the string, one from the front and one from the back. Complexity is linear, thus O(n).
Now, doing it in a single pass ... I'd have to think a bit about that.
This works, uses linq, and has O(n) time complexity:
var input = #"123vcvcv00191pololo";
var array =
input
.ToCharArray()
.Where(c => !Char.IsDigit(c))
.Concat(
input
.ToCharArray()
.Where(c => Char.IsDigit(c)))
.ToArray();
var output = new String(array);
Console.Write(output);
// vcvcvpololo12300191
using linq's OrderBy as shown should move all the digits to the end of the string/char[] in the order in which they appear in the string.
var input = #"123vcvcv00191pololo";
var array = input.ToCharArray().OrderBy(c => Char.IsDigit(c)).ToArray();
var output = new String(array);
Console.Write(output);
//vcvpololo12300191

project euler 22 using c#

I am solving the same problem as here Project Euler #22 Python, 2205 points missing?, but I am using C#. I can't find the mistake. Here is my code:
class Program
{
static List<string> pole;
static string SaveName(StreamReader reader)
{
int znak = reader.Read();
string jmeno = "";
while ((znak < 'A') || (znak > 'Z'))
{
znak = reader.Read();
}
while (znak != ',')
{
jmeno = jmeno + (char) znak;
znak = reader.Read();
if (znak == 34) break;
}
return jmeno;
}
static void SaveNamesIntoList()
{
StreamReader reader = new StreamReader(#"../../../names.txt");
while (reader.Read() != ';')
{
pole.Add(SaveName(reader));
}
}
static void Main(string[] args)
{
pole = new List<string>();
SaveNamesIntoList();
pole.Sort();
int sum = 0;
int sum_word = 0;
string name = "";
for (int i = 0; i < pole.Count; i++)
{
name = pole[i];
sum_word = 0;
for (int u = 0; u < name.Length; u++)
{
sum_word += (name[u] - 'A' + 1);
}
sum += (sum_word * (i+1));
}
Console.WriteLine(sum);
}
}
Thanks for any answer:)
Ther reason why you have different result is than Czech language has specific letter 'CH' whitch is after 'H' so in alfabetical order without using right culture you can have sometring like this
aaa
bbb
ccc
czz
ddd
cha
There are a few issues here. You don't check if the reader reached the end of stream - you have to check if the Read returned -1. If it did - it's the end of the file. On top of that, you don't dispose the reader...
Then, as Cedric noted in the comments, you haven't really sorted the list, hence the result is wrong even after changing it to:
using (var reader = new StreamReader("names.txt"))
{
while (reader.Read() != -1)
{
pole.Add(SaveName(reader));
}
}
What you need to do is add this line (which is a bit wasteful in general, but I'll get to that in a sec):
pole = pole.OrderBy(x => x).ToList(); //<<----- this one
for (int i = 0; i < pole.Count; i++)
{
name = pole[i];
sum_word = 0;
for (int u = 0; u < name.Length; u++)
{
sum_word += (name[u] - 'A' + 1);
}
sum2 += (sum_word*(i + 1));
}
And the result is 871198282, which should be correct - at least that's what the people are saying in the linked question.
Even then, might I suggest an easier way of solving that whole problem:
var scores = Enumerable.Range('A', 'Z' - 'A' + 1)
.Select((i, ch) => new { Character = (char) i, Weight = ch + 1 })
.ToDictionary(key => key.Character, val => val.Weight);
var sum = File.ReadAllText("names.txt")
.Split(',')
.Select(x => x.Trim('"'))
.OrderBy(x => x)
.Select((x, i) => (i + 1)*x.Select(y => scores[y]).Sum())
.Sum();
Here's a version using Linq.
void Main()
{
var file = #"C:\...location.of.file...\p022_names.txt";
using (var reader = new StreamReader(file, Encoding.UTF8))
{
NameScore(reader.ReadToEnd().Replace("\"",string.Empty).Split(new[]{','})).Dump();
}
}
private long NameScore(string[] names)
{
return names.OrderBy(o => o)
.Select((l, i) => { return l.ToUpper().ToCharArray().Sum(s => (int)s - 64) * (i + 1);})
.Sum(s => s);
}

Create all permutations of a string incrementally c#

I am trying to create a function that will create all permutations of a string in an incremental fashion. I would like to start at:
AAAAA
...
AAAAB
...
ACCCC
...
...
ZZZZZ
I have looked around, and can't seem to find anything of that sort. I tried to create it, but it wasn't incrementally.
Any suggestions?
The "permutation" you are describing is better known as the Cartesian product. If you have an arbitrary number of sequences that you need to form the Cartesian product of, see my answer to this question on the subject:
Generating all Possible Combinations
Normally I wouldn't help these brute force type results... but seeing how many useless result you will get out of the set I figured I'd just toss this in.
var query = from c0 in Enumerable.Range(0, 26)
from c1 in Enumerable.Range(0, 26)
from c2 in Enumerable.Range(0, 26)
from c3 in Enumerable.Range(0, 26)
from c4 in Enumerable.Range(0, 26)
select new string(
new [] {
(char)('A' + c0),
(char)('A' + c1),
(char)('A' + c2),
(char)('A' + c3),
(char)('A' + c4),
}
);
BTW... if you just want the next value you can do something like this...
public static string Increment(string input)
{
var array = input.ToCharArray();
if (array.Any(c => c < 'A' || c > 'Z'))
throw new InvalidOperationException();
for (var i = array.Length-1; i >= 0; i--)
{
array[i] = (char)(array[i] + 1);
if (array[i] > 'Z')
{
array[i] = 'A';
if (i == 0)
return 'A' + new string(array);
}
else
break;
}
return new string(array);
}
A different variant where I had the idea of using modulo arithmetic. Note that I lowered the character to {A,B,C} to test it, since going up to Z for 5 letters is a lot of strings.
public IEnumerable<char[]> AlphaCombinations(int length = 5, char startChar = 'A', char endChar = 'C')
{
int numChars = endChar - startChar + 1;
var s = new String(startChar, length).ToCharArray();
for (int it = 1; it <= Math.Pow(numChars, length); ++it)
{
yield return s;
for (int ix = 0; ix < s.Length; ++ix)
if (ix == 0 || it % Math.Pow(numChars, ix) == 0)
s[s.Length - 1 - ix] = (char)(startChar + (s[s.Length - 1 - ix] - startChar + 1) % numChars);
}
}
...
foreach (var s in AlphaCombinations(5))
{
Console.WriteLine(s);
}
Bashed out quickly - I expect this could be done better:
public static IEnumerable<string> GenerateStrings(int length = 5)
{
var buffer = new char[length];
for (int i = 0; i < length; ++i)
{
buffer[i] = 'A';
}
for(;;)
{
yield return new string(buffer);
int cursor = length;
for(;;)
{
--cursor;
if (cursor < 0)
{
yield break;
}
char c = buffer[cursor];
++c;
if (c <= 'Z')
{
buffer[cursor] = c;
break;
}
else
{
buffer[cursor] = 'A';
}
}
}
}
Here is the LINQPad friendly code and it uses lambda expression.
void Main()
{
var chars = Enumerable.Range(65, 26);
var strings = chars.SelectMany (a =>
{
return chars.SelectMany (b => chars.SelectMany (c =>
{
return chars.SelectMany (d =>
{
return chars.Select (e => {return new string(new char[] {(char)a, (char)b, (char)c, (char)d, (char)e});});
});
}));
});
strings.Dump();
}

Categories

Resources