C# - 从字符串中获取所有子字符串的代码优化

时间:2018-03-20 05:56:36

标签: c# optimization

我正在编写代码片段以获取给定字符串中的所有子字符串。

以下是我使用的代码

 var stringList = new List<string>();
 for (int length = 1; length < mainString.Length; length++)
 {
    for (int start = 0; start <= mainString.Length - length; start++)
    {
       var substring = mainString.Substring(start, length);
       stringList.Add(substring);
    }
 }

对我而言看起来并不那么好,有两个for循环。有没有其他方法可以通过更好的时间复杂度实现这一目标。

我坚持认为,为了获得子串,我肯定需要两个循环。还有其他方法可以研究吗?

4 个答案:

答案 0 :(得分:6)

字符串中的子串数是O(n^2),因此在另一个中的一个循环是您可以做的最好的。你的代码结构是正确的。

以下是我将如何表达您的代码:

void Main()
{
    var stringList = new List<string>();
    string s = "1234";
    for (int i=0; i <s.Length; i++)
        for (int j=i; j < s.Length; j++)
            stringList.Add(s.Substring(i,j-i+1));
}

答案 1 :(得分:2)

在某些情况下,您可以通过减少对象分配来显着提高执行速度。在这种情况下,使用单个char[]ArraySegment<of char>来处理子字符串。这也将导致使用更少的地址空间并减少垃圾收集器负载。

Microsoft Docs上Using the StringBuilder Class in .NET页面的相关摘录:

  

String对象是不可变的。每次使用System.String类中的一个方法时,都会在内存中创建一个新的字符串对象,这需要为该新对象分配新的空间。在需要对字符串执行重复修改的情况下,与创建新String对象相关的开销可能会很昂贵。

示例实施:

static List<ArraySegment<char>> SubstringsOf(char[] value)
{
    var substrings = new List<ArraySegment<char>>(capacity: value.Length * (value.Length + 1) / 2 - 1);
    for (int length = 1; length < value.Length; length++)
        for (int start = 0; start <= value.Length - length; start++)
            substrings.Add(new ArraySegment<char>(value, start, length));
    return substrings;
}

有关详情,请查看Microsoft文档上的Fundamentals of Garbage Collection页面,关于StackOverflow的what is the use of ArraySegment class?讨论,MSDN上的ArraySegment<T> Structure页面和MSDN上的List<T>.Capacity页面。

答案 2 :(得分:1)

您确实需要2个String mName = "",mAdd="",mPhn="",mSal="",mLea=""; if (getIntent().hasExtra("name")) { mName = getIntent().getExtras().getString("name"); mAdd = getIntent().getExtras().getString("add"); mPhn = getIntent().getExtras().getString("phn"); mSal = getIntent().getExtras().getString("sal"); mLea = getIntent().getExtras().getString("lea"); } name.setText(mName); address.setText(mAdd); contact.setText(mPhn); salary.setText(mSal); leaves.setText(mLea); 循环

Demo here

for

更新

您无法改进迭代。

但是,您可以使用var input = "asd sdf dfg"; var stringList = new List<string>(); for (int i = 0; i < input.Length; i++) { for (int j = i; j < input.Length; j++) { var substring = input.Substring(i, j-i+1); stringList.Add(substring); } } foreach(var item in stringList) { Console.WriteLine(item); } 数组和指针

来提高性能

答案 3 :(得分:0)

好吧,O(n**2) 时间复杂性是不可避免的,但是你可以尝试推动 space 消费。在许多情况下,您不希望所有子字符串具体化,例如List<string>

public static IEnumerable<string> AllSubstrings(string value) {
  if (value == null) 
    yield break; // Or throw ArgumentNullException

  for (int length = 1; length < value.Length; ++length)
    for (int start = 0; start <= value.Length - length; ++start)
      yield return value.Substring(start, length);
}

例如,让我们计算"abracadabra"中从a开始且长于3个字符的所有子字符串。请注意,我们所要做的就是循环 over susbstrings ,不用将它们保存到列表中:

int count = AllSubstrings("abracadabra")
  .Count(item => item.StartsWith("a") && item.Length > 3);

如果出于任何原因需要List<string>,只需添加.ToList()

var stringList = AllSubstrings(mainString).ToList();