1

Given a string I want to swap 2 characters in the string based on their indices.

Input : str = "Hello" index1 = 1 index2 = 4

Output : str = "Holle"

but when I directly try updating the string character :

str[1] = //Assign something 

it gives the error ->

Property or indexer 'string.this[int]' cannot be assigned to -- it is read only

So I wrote a function that converts the string to character array before performing the swap operation.

static string SwapChars(String str, int index1, int index2)
{
    char[] strChar = str.ToCharArray();
    char temp = strChar[index1];
    strChar[index1] = strChar[index2];
    strChar[index2] = temp;
    
    return new String(strChar);
}

It is working fine, but I want to know what is the time complexity for the function. I think it is O(n) as char array and string are getting constructed as new, where n is length of string passed. Also is there some other way I can perform this operation with better performance.

Jasmeet
  • 1,315
  • 11
  • 23

4 Answers4

5

The string cannot assign value through indexer because it's not allowed to do that. When you look up at the definition of string, find for this[int index] you will know it only allowed get

enter image description here

The best way to swap them is base on your method, but have no temp value.

static string SwapChars(String str, int index1, int index2)
{
    char[] strChar = str.ToCharArray();
    strChar[index1] = str[index2];
    strChar[index2] = str[index1];
    
    return new String(strChar);
}

Another option is using Insert and Remove

static string SwapChars(String str, int index1, int index2)
{
    return str.Remove(index1, 1).Insert(index1, str[index2].ToString())
            .Remove(index2, 1).Insert(index2, str[index1].ToString());
}

Honestly, I prefer the first one because it's clear.

Tấn Nguyên
  • 1,607
  • 4
  • 15
  • 25
1

according to this link, one way to replace chars in string is using StringBuilder class in c#,

var str = "Hello";
var strBuilder = new StringBuilder(str);
strBuilder[4] = 'e';

str = strBuilder.ToString();
// the result will be same 

in this link compare c# String function and StringBuilder, if you will you can compare this two function.

EDIT NOTE:

I tested both StringBuilder and ToCharArray methods, the results shows that using ToCharArray and replace the char is really better than using StringBuilder function, here is my tested code(at least in my machine ) :

var str = new String('a' , 100000000);

var stopwatch = new Stopwatch();

stopwatch.Start();
var strBuilder = new StringBuilder(str);
strBuilder[4] = 'e';

str = strBuilder.ToString();
stopwatch.Stop();
Console.WriteLine("Elapsed time using StringBuilder: {0} ms", stopwatch.Elapsed.Milliseconds);

stopwatch.Reset();
stopwatch.Start();
char[] strChar = str.ToCharArray();
char temp = strChar[1];
strChar[1] = strChar[4];
strChar[4] = temp;

stopwatch.Stop();
Console.WriteLine("Elapsed time using ToCharArray: {0} ms", stopwatch.Elapsed.Milliseconds);


/*
  results: 
    Elapsed time using StringBuilder: 179 ms
    Elapsed time using ToCharArray: 94 ms
*/
Ali Bigdeli
  • 1,286
  • 3
  • 17
  • 35
  • I think the time complexity/performance in above solution will be the same to that of converting it to char array. – Jasmeet Aug 02 '20 at 08:04
1

You could use pointers, with minimal allocations

public unsafe void SwapChars(ref string str, int index1, int index2)
{
   fixed (char* p = str)
   {
      var temp = p[index1];
      p[index1] = p[index2];
      p[index2] = temp;
   }
}

Note the above is fairly dangerous, as it will mess-up unturned strings

This would be safer

public static unsafe string SwapChars(string str, int index1, int index2)
{
   if (str == null) throw new ArgumentNullException(nameof(str));
   if (index1 < 0 || index1 >= str.Length) throw new ArgumentOutOfRangeException(nameof(index1));
   if (index2 < 0 || index2 >= str.Length) throw new ArgumentOutOfRangeException(nameof(index1));

   var result = new string(str);

   fixed (char* p = result)
   {
      var temp = p[index1];
      p[index1] = p[index2];
      p[index2] = temp;
   }
   return result;
}
TheGeneral
  • 79,002
  • 9
  • 103
  • 141
  • I am sure this will have constant time complexity. I just want to know as we are using pointers is there any special precautions or undefined behaviour I need to consider. The code you wrote looks pretty straightforward though. – Jasmeet Aug 02 '20 at 08:46
  • @Jasmeet you would want to check the indexes against the length, otherwise you might get a memory exception. ie. just do some input validation beforehand – TheGeneral Aug 02 '20 at 09:04
  • The output of this ` string test = "abcde"; SwapChars(ref test, 1, 4); Console.WriteLine(test); test = "abcde"; Console.WriteLine(test); ` is not expected, it is (`aecdb aecdb`) – Luuk Aug 02 '20 at 09:07
  • `var result = new string(str);` says: `cannot convert from 'string' to 'char*'`, solving this one would have to do `var result = new string(str.ToCharArray());` but that would defeat the purpose of it having 'better performance'.... – Luuk Aug 02 '20 at 09:23
  • I havnt got time to continue with this answer, if there is an issue feel free to copy fix and paste your own answer. I'll have a further look in the morning – TheGeneral Aug 02 '20 at 10:06
1

I want to know what is the time complexity for the function

If n is "copying a char from one memory location to another" then it's O(2n+3)

Your string chars are copied to a char array, you swap them, the chars are copied to another string

Caius Jard
  • 72,509
  • 5
  • 49
  • 80