【问题标题】:Optimizing this C# algorithm (K Difference)优化此 C# 算法(K 差)
【发布时间】:2011-10-08 08:42:36
【问题描述】:

这是我要解决的问题(这是一个示例问题,不是真正的问题):

给定 N 个数字,[N0 和 K

输入格式:第一行包含 N 和 K(整数)。第二行包含 N 集合的编号。确保所有 N 个数字都是不同的。 输出格式:一个整数表示具有的数字对的数量 一个差异K。

Sample Input #00:
5 2
1 5 3 4 2
Sample Output #00:
3
Sample Input #01:
10 1
363374326 364147530 61825163 1073065718 1281246024 1399469912 428047635 491595254 879792181 1069262793 
Sample Output #01:
0

我已经有了一个解决方案(但我无法像我希望的那样优化它)。目前,我的解决方案在运行时获得了 12/15 的分数,我想知道为什么我不能获得 15/15(我对另一个问题的解决方案效率不高,但是得到所有的分数)。显然,代码是使用“Mono 2.10.1, C# 4”运行的。

那么有人能想出更好的方法来进一步优化吗? VS 分析器说要避免调用 String.Split 和 Int32.Parse。对 Int32.Parse 的调用无法避免,尽管我想我可以优化对数组的标记。

我目前的解决方案:

using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;

namespace KDifference
{
   class Solution
   {
      static void Main(string[] args)
      {
         char[] space = { ' ' };

         string[] NK = Console.ReadLine().Split(space);
         int N = Int32.Parse(NK[0]), K = Int32.Parse(NK[1]);

         int[] nums = Console.ReadLine().Split(space, N).Select(x => Int32.Parse(x)).OrderBy(x => x).ToArray();

         int KHits = 0;

         for (int i = nums.Length - 1, j, k; i >= 1; i--)
         {
            for (j = 0; j < i; j++)
            {
               k = nums[i] - nums[j];

               if (k == K)
               {
                  KHits++;
               }
               else if (k < K)
               {
                  break;
               }
            }
         }

         Console.Write(KHits);
      }
   }
}

【问题讨论】:

  • 不注册我们看不到这个问题。您能否发布您的评分标准?
  • 是的,对不起。我以为它对所有人开放。具体评分标准没有公布,但代码经过了一堆测试运行。
  • 你会因为速度慢而扣分吗?还是因为错了?还是两者兼而有之?

标签: c# optimization


【解决方案1】:

您的算法仍然是 O(n^2),即使有排序和提前退出。即使你消除了 O(n^2) 位,排序仍然是 O(n lg n)。 您可以使用 O(n) 算法来解决此问题。这是一种方法:

假设你的集合是S1 = { 1, 7, 4, 6, 3 },差是2。

构造集合S2 = { 1 + 2, 7 + 2, 4 + 2, 6 + 2, 3 + 2 } = { 3, 9, 6, 8, 5 }

您寻求的答案是 S1 和 S2 交集的基数。交集是{6, 3},它有两个元素,所以答案是2。

只要你有整数序列sequence和整数difference,你就可以在一行代码中实现这个解决方案:

int result = sequence.Intersect(from item in sequence select item + difference).Count();

Intersect 方法将为您构建一个高效的哈希表,用 O(n) 来确定交集。

【讨论】:

  • 这个算法确实令人印象深刻。你能提供一些关于这些算法的资源吗?
  • @Eric Lippert : 是否可以在没有 o(n^2) 复杂度的情况下找到两个数组的交集?
  • @Chetna:我给出了一个用于序列的 O(n) 算法。数组是一个序列。所以,是的。
【解决方案2】:

试试这个(注意,未经测试):

  1. 对数组进行排序
  2. 从 0 开始两个索引
  3. 如果这两个位置的数字之差等于 K,则增加计数,并增加两个索引之一(如果数字不重复,则同时增加)
  4. 如果差值大于 K,则增加索引 #1
  5. 如果差值小于 K,则增加索引 #2,如果这样会将其放在数组之外,则完成
  6. 否则,回到 3 继续前进

基本上,尽量让两个索引相差K值。

您应该为您的算法编写一系列单元测试,并尝试提出极端情况。

【讨论】:

  • "所有N个数字都保证是不同的。"
  • O(n log n) 而不是同样简单的 O(n) 解决方案。
【解决方案3】:

这将允许您一次性完成。如果要解析/检查许多值,则使用哈希集是有益的。您可能还希望将 bloom filter 与哈希集结合使用以减少查找。

  1. 初始化。AB 为两个空哈希集。让 c 为零。
  2. 解析循环。解析下一个值v。如果没有更多值,则算法完成并且结果在 c 中。
  3. 回查。如果v存在于A中,则递增c并跳回2。强>
  4. 低匹配。 如果 v - K > 0 则:
    • v - K 插入 A
    • 如果 v - K 存在于 B 中,则增加 c (并可选择从 v - K em>B)。
  5. 高度匹配。 如果 v + K 则:
    • v + K 插入 A
    • 如果 v + K 存在于 B 中,则增加 c (并可选择从 v + K 中删除em>B
    )。
  6. 记住。v 插入 B
  7. 跳回2.

【讨论】:

    【解决方案4】:

    //这个k差异的php解决方案

    function getEqualSumSubstring($l,$s) {
    $s = str_replace(' ','',$s);
    $l = str_replace(' ','',$l);
    
    for($i=0;$i<strlen($s);$i++)
    {
       $array1[] = $s[$i];
    }
    for($i=0;$i<strlen($s);$i++)
    {
       $array2[] = $s[$i] + $l[1];
    }
    return count(array_intersect($array1,$array2));
    
    }
    
    echo getEqualSumSubstring("5 2","1 3 5 4 2");
    

    【讨论】:

      【解决方案5】:

      其实用 hashmap 解决这个问题很简单:

      首先将每个数字放入一个哈希图中:“pythony”伪代码中的dict((x, x) for x in numbers) ;)

      现在您只需遍历哈希图中的每个数字并检查数字 + K 是否在哈希图中。如果是,则将计数加一。

      对天真的解决方案的明显改进是只检查上限(或下限),否则你会得到双倍的结果,然后必须除以 2 - 没用。

      这是在读取值时创建哈希图的 O(N) 和迭代时的 O(N),即 O(N) 和 python 中的大约 8loc(这是正确的,我刚刚解决了它;-) )

      【讨论】:

        【解决方案6】:

        按照 Eric 的回答,将 Interscet 方法的实现粘贴到下面,它是 O(n):

        private static IEnumerable<TSource> IntersectIterator<TSource>(IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
        {
            Set<TSource> set = new Set<TSource>(comparer);
            foreach (TSource current in second)
            {
                set.Add(current);
            }
            foreach (TSource current2 in first)
            {
                if (set.Remove(current2))
                {
                    yield return current2;
                }
            }
            yield break;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-09-06
          • 2021-06-29
          • 2012-09-05
          • 1970-01-01
          • 2016-04-15
          • 2023-03-09
          相关资源
          最近更新 更多