如何进行 d-平滑序列算法

How to go about a d-smooth sequence algorithm

我真的很努力地设计一个算法来找到 d,它是可以添加或减去(最多)以使给定序列严格递增的最低值。

例如..说seq[] = [2,4,8,3,1,12]

给定该序列,算法应该 return“5”作为 d,因为您最多可以为每个元素加减 5,以便函数严格递增。

我尝试了几种方法,但似乎无法掌握可靠的技术。

我试过循环遍历 seq。并检查 seq[i] < seq[i+1]。如果不是,它检查是否 d>0.. 如果是,尝试从 seq[i+1] 中 add/subtract 它。否则它通过取 seq[i-1] - seq[i].

的差来计算 d

虽然我无法使其稳定,但它就像我一直在添加 if 语句,这些语句对于独特的输入序列来说更“特殊”。人们建议使用二进制搜索方法,但我无法将其应用于此问题。

非常感谢任何提示和建议。谢谢!


这是我正在编写的代码 - 使用 Python - v4

def ComputeMaxDelta3(seq):
    # Create a copy to speed up comparison on modified values
    aItems = seq[1:] #copies sequence elements from 1 (ignores seq[0])
    # Will store the fix values for every item
    # this should allocate 'length' times the 0 value
    fixes = [0] * len(aItems)
    print("fixes>>",fixes)

    # Loop until no more fixes get applied
    bNeedFix = True
    while(bNeedFix):
        # Hope will have no fix this turn
        bNeedFix = False

        # loop all subsequent item pairs (i should run from 0 to length - 2)
        for i in range(0,len(aItems)-1):
            # Left item
            item1 = aItems[i]
            # right item
            item2 = aItems[i+1]

            # Compute delta between left and right item
            # We remember that (right >= left + 1
            nDelta = item2 - (item1 + 1)
            if(nDelta < 0):
                # Fix the right item
                fixes[i+1] -= nDelta
                aItems[i+1] -= nDelta
                # Need another loop
                bNeedFix = True

    # Compute the fix size (rounded up)
    # max(s) should be int and the division should produce an int
    nFix = int((max(fixes)+1)/2)
    print("current nFix:",nFix)
    

    # Balance all fixes
    for i in range(len(aItems)):
        fixes[i] -= nFix

    print("final Fixes:",fixes)
    print("d:",nFix)
    print("original sequence:",seq[1:])
    print("result sequence:",aItems)

    return

显示的内容如下:

Working with: [6, 2, 4, 8, 3, 1, 12] 
    [0]= 6 So the following numbers are the sequence: 
         aItems = [2, 4, 8, 3, 1, 12] 

fixes>> [0, 0, 0, 0, 0, 0]
current nFix: 6
final Fixes: [-6, -6, -6, 0, 3, -6]
d: 1
original sequence: [2, 4, 8, 3, 1, 12]
result sequence: [2, 4, 8, 9, 10, 12]

d SHOULD be: 5

done!

~注意~

我从 1 而不是 0 开始,因为第一个元素是键

这是我的解决方案:

public static int ComputeMaxDelta(int[] aItems, out int[] fixes)
{
    // Create a copy to speed up comparison on modified values
    aItems = (int[])aItems.Clone();
    // Will store the fix values for every item
    fixes = new int[aItems.Length];

    // Loop until no more fixes get applied
    var bNeedFix = true;
    while (bNeedFix)
    {
        // Hope will have no fix this turn
        bNeedFix = false;

        // loop all subsequent item pairs
        for (int ixItem = 0; ixItem < aItems.Length - 1; ixItem++)
        {
            // Left item
            var item1 = aItems[ixItem];
            // right item
            var item2 = aItems[ixItem + 1];

            // Compute delta between left and right item
            // We remember that (right >= left + 1)
            var nDelta = item2 - (item1 + 1);
            if (nDelta < 0)
            {
                // Fix the right item
                fixes[ixItem + 1] -= nDelta;
                aItems[ixItem + 1] -= nDelta;
                //Need another loop
                bNeedFix = true;
            }
        }
    }

    // Compute the fix size (rounded up)
    var nFix = (fixes.Max() + 1) / 2;

    // Balance all fixes
    for (int ixItem = 0; ixItem < aItems.Length; ixItem++)
        fixes[ixItem] -= nFix;

    return nFix;
}

函数returns计算出的最大修复间隙。 作为奖励,参数修复将收到每个项目的修复。这些是应用于每个源值的增量,以确保它们按升序排列:可以减少一些修复,但需要一些分析循环来实现该优化。


以下是算法测试代码。如果您在循环结束时设置断点,您将能够检查您在示例中提供的序列的结果。

var random = new Random((int)Stopwatch.GetTimestamp());
for (int ixLoop = -1; ixLoop < 100; ixLoop++)
{
    int nCount;
    int[] aItems;

    // special case as the provided sample sequence
    if (ixLoop == -1)
    {
        aItems = new[] { 2, 4, 8, 3, 1, 12 };
        nCount = aItems.Length;
    }
    else
    {
        // Generates a random amount of items based on my screen's width
        nCount = 4 + random.Next(21);
        aItems = new int[nCount];
        for (int ixItem = 0; ixItem < nCount; ixItem++)
        {
            // Keep the generated numbers below 30 for easier human analysis
            aItems[ixItem] = random.Next(30);
        }
    }

    Console.WriteLine("***");
    Console.WriteLine("  # " + GetText(Enumerable.Range(0, nCount).ToArray()));
    Console.WriteLine("    " + GetText(aItems));

    int[] aFixes;
    var nFix = ComputeMaxDelta(aItems, out aFixes);

    // Computes the new values, that will be always in ascending order
    var aNew = new int[aItems.Length];
    for (int ixItem = 0; ixItem < aItems.Length; ixItem++)
    {
        aNew[ixItem] = aItems[ixItem] + aFixes[ixItem];
    }

    Console.WriteLine("  = " + nFix.ToString());
    Console.WriteLine("  ! " + GetText(aFixes));
    Console.WriteLine("  > " + GetText(aNew));
}

此致,
丹尼尔.

正如预期的那样,这是(或应该是)我最初解决方案的 Python 版本:

def ComputeMaxDelta(aItems):
    # Create a copy to speed up comparison on modified values
    aItems = aItems[:]
    # Will store the fix values for every item
    # this should allocate 'length' times the 0 value
    fixes = [0] * len(aItems)

    # Loop until no more fixes get applied
    bNeedFix = True
    while(bNeedFix):
        # Hope will have no fix this turn
        bNeedFix = False

        # loop all subsequent item pairs (i should run from 0 to length - 2)
        for i in range(0,len(aItems)-1):
            # Left item
            item1 = aItems[i]
            # right item
            item2 = aItems[i+1]

            # Compute delta between left and right item
            # We remember that (right >= left + 1
            nDelta = item2 - (item1 + 1)
            if(nDelta < 0):
                # Fix the right item
                fixes[i+1] -= nDelta
                aItems[i+1] -= nDelta
                # Need another loop
                bNeedFix = True

    # Compute the fix size (rounded up)
    # max(s) should be int and the division should produce an int
    nFix = (max(fixes)+1)/2 # corrected from **(max(s)+1)/2**

    # Balance all fixes
    for i in range(len(s)):
        fixes[i] -= nFix

    print("d:",nFix) # corrected from **print("d:",nDelta)**
    print("s:",fixes)

    return

我采用了您的 Python 并进行了修复,以便完全按照我的 C# 解决方案运行。 我不知道 Python,但在网上寻找一些参考资料,我应该找到你移植失败的地方。

如果将您的 python 版本与我的进行比较,您应该会发现以下差异:

  1. 您将引用 aItems 保存到 s 并将其用作我的 fixes,但是fixes 本来是从 0 开始的。
  2. 您没有在自身上克隆 aItems,然后对其项目的每个更改都反映在方法之外。
  3. 你的 for 循环从索引 1 开始,而我的循环从 0(第一个元素)开始。
  4. 检查 nDelta 后,您从 s 和 [=21] 中减去 nDelta =]aItems,但正如我在第 1 点和第 2 点所述,它们指向相同的项目。
  5. 不需要 ceil 指令,因为两个整数之间的除法产生一个整数,与 C# 一样。

请记住,我仅根据在线文档知识修复了 Python 代码,因为我不使用该语言编写代码,所以我不能 100% 确定某些语法(我的主要疑问关于 fixes 声明)。

此致,
丹尼尔.