поменять местами 2 символа в строке на основе их индексов - PullRequest
0 голосов
/ 02 августа 2020

Учитывая строку, я хочу поменять местами 2 символа в строке на основе их индексов.

Вход: str = "Hello" index1 = 1 index2 = 4

Выход: str = "Holle"

, но когда я напрямую пытаюсь обновить строковый символ:

str[1] = //Assign something 

, появляется ошибка ->

Свойство или indexer 'string.this [int]' не может быть назначен - он доступен только для чтения

Поэтому я написал функцию, которая преобразует строку в массив символов перед выполнением операции свопинга.

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);
}

Он работает нормально, но я хочу знать, какова временная сложность функции. Я думаю, что это O (n), поскольку массив char и строка создаются как новые, где n - длина переданной строки. Также есть другой способ выполнить эту операцию с большей производительностью.

Ответы [ 4 ]

1 голос
/ 02 августа 2020

Я хочу знать, какова временная сложность функции

Если n - это «копирование символа из одной ячейки памяти в другую», то это O (2n + 3 )

Ваши строковые символы копируются в массив символов, вы меняете их местами, символы копируются в другую строку

1 голос
/ 02 августа 2020

Строке нельзя присвоить значение через индексатор, потому что это не разрешено. Когда вы посмотрите на определение string, найдите для this[int index], вы узнаете, что это разрешено только get

введите описание изображения здесь

Лучший способ их поменять местами основан на вашем методе, но не имеет значения temp.

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);
}

Другой вариант - использовать Insert и 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());
}

Честно говоря, я предпочитаю первый, потому что он ясный.

1 голос
/ 02 августа 2020

Вы можете использовать указатели с минимальными выделениями

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;
   }
}

Обратите внимание, что приведенное выше довольно опасно, так как это приведет к испорчению неперевернутых строк

Это было бы безопаснее

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;
}
0 голосов
/ 02 августа 2020

согласно этой ссылке, один из способов заменить символы в строке - использовать StringBuilder class в c#,

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

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

in this link сравните c# String функцию и StringBuilder, если хотите, вы можете сравнить эти две функции.

РЕДАКТИРОВАТЬ ПРИМЕЧАНИЕ:

Я тестировал методы StringBuilder и ToCharArray, результаты показывают, что использование ToCharArray и замена char действительно лучше, чем использование функции StringBuilder, вот мой протестированный код (по крайней мере, на моей машине):

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
*/
...