检查整数序列是否递增

2024-01-12

我只部分地解决了下面的问题。

给定一个整数序列,检查是否可以通过删除不超过一个元素来获得严格递增的序列。

Example

sequence = [1, 3, 2, 1]
almostIncreasingSequence(sequence) = false

sequence = [1, 3, 2]
almostIncreasingSequence(sequence) = true

我的代码仅传递一些示例:

bool almostIncreasingSequence(int[] sequence) {
   int seqIncreasing = 0;
    if (sequence.Length == 1) return true;
    for (int i = 0;i < sequence.Length-2;i++)
    {
        if ((sequence[i] == sequence[++i]+1)||(sequence[i] == sequence[++i])) 
        {
            seqIncreasing++; 
        } 
    } 
    return ((seqIncreasing == sequence.Length) || (--seqIncreasing == sequence.Length));
}

失败的例子:

Input:
    sequence: [1, 3, 2]
Output:
    false
Expected Output:
    true

Input:
    sequence: [10, 1, 2, 3, 4, 5]
Output:
    false
Expected Output:
    true

Input:
    sequence: [0, -2, 5, 6]
Output:
    false
Expected Output:
    true

Input:
    sequence: [1, 1]
Output:
    false
Expected Output:
    true

基于 LINQ 的答案很好,并且很好地表达了基本问题。简单易读,易于理解,直接解决问题。然而,它确实存在一个问题,即它需要为原始序列中的每个元素生成一个新序列。随着序列变得越来越长,这会变得更加昂贵并且最终变得棘手。

它没有帮助,它需要使用Skip() and Take(),它们本身增加了处理原始序列的开销。

另一种方法是扫描序列一次,但跟踪是否已尝试删除,并且当发现失序元素时,a)立即返回false如果已经发现删除,并且 b) 在确定序列时不包括删除的元素。

您尝试过的代码almost实现这一点。这是一个有效的版本:

static bool almostIncreasingSequence(int[] sequence)
{
    bool foundOne = false;

    for (int i = -1, j = 0, k = 1; k < sequence.Length; k++)
    {
        bool deleteCurrent = false;

        if (sequence[j] >= sequence[k])
        {
            if (foundOne)
            {
                return false;
            }
            foundOne = true;

            if (k > 1 && sequence[i] >= sequence[k])
            {
                deleteCurrent = true;
            }
        }

        if (!foundOne)
        {
            i = j;
        }

        if (!deleteCurrent)
        {
            j = k;
        }
    }

    return true;
}

注意:我最初认为您的尝试可以通过微小的改变来修复。但最终,事实证明它必须与我编写的通用实现本质上相同(特别是当我也修复了该实现之后......见下文)。唯一的实质性区别实际上只是使用数组还是泛型IEnumerable<T>.

为了一笑,我编写了另一种方法,该方法符合基于 LINQ 的解决方案的脉络,因为它适用于任何序列,而不仅仅是数组。我还使它成为通用的(尽管有类型实现的约束)IComparable<T>)。看起来像这样:

static bool almostIncreasingSequence<T>(IEnumerable<T> sequence) where T : IComparable<T>
{
    bool foundOne = false;
    int i = 0;
    T previous = default(T), previousPrevious = default(T);

    foreach (T t in sequence)
    {
        bool deleteCurrent = false;

        if (i > 0)
        {
            if (previous.CompareTo(t) >= 0)
            {
                if (foundOne)
                {
                    return false;
                }

                // So, which one do we delete? If the element before the previous
                // one is in sequence with the current element, delete the previous
                // element. If it's out of sequence with the current element, delete
                // the current element. If we don't have a previous previous element,
                // delete the previous one.

                if (i > 1 && previousPrevious.CompareTo(t) >= 0)
                {
                    deleteCurrent = true;
                }

                foundOne = true;
            }
        }

        if (!foundOne)
        {
            previousPrevious = previous;
        }

        if (!deleteCurrent)
        {
            previous = t;
        }
        i++;
    }

    return true;
}

当然,如果您愿意将原始序列复制到临时数组中(如果它还不是临时数组),那么您可以轻松地使基于数组的版本通用,这将使代码更简单,但仍然通用。这仅取决于您的优先事项是什么。

附录:

LINQ 方法和线性方法(例如上面我的方法)之间的基本性能差异是显而易见的,但我很好奇并想量化这种差异。因此,我使用随机生成的序列进行了一些测试,以粗略地了解差异。

我执行了两个版本的测试:第一个,我运行了 1000 次试验的循环,其中序列的长度可以在 10 到 100 个元素之间;第二个是 10,000 次试验,序列长度在 100 到 1000 个元素之间。我执行了第二个版本,因为在我的笔记本电脑上,1000 次试验的整个测试用较短的序列在不到 1/20 秒内完成,时间太短,让我对结果的有效性没有信心。

在第一个版本中,代码调用线性检查方法花费了大约 1 毫秒,调用 LINQ 方法花费了大约 30 毫秒,速度相差了 30 倍。将试验次数增加到 10,000 次证实了结果;每种方法的时间几乎精确地缩放了 10 倍,保持了 30 倍的差异。

在第二个版本中,差异接近400x。线性版本大约需要 0.07 秒,而 LINQ 版本需要 30 秒。

正如预期的那样,序列越长,差异越严重。对于非常短的序列,不仅代码不太可能在序列检查逻辑上花费太多时间,而且线性方法和 LINQ 方法之间的差异也相对较小。但随着序列变长,这种差异将导致 LINQ 版本的性能非常差,而线性版本仍然表现出色。

LINQ 版本是very可读且简洁。因此,在输入总是相对较短(最多十两个元素的量级)的情况下,我会选择 LINQ 版本。但是,如果我希望使用比这更长的数据定期执行此测试,我将避免使用 LINQ 并坚持使用更高效的线性方法。


关于随机生成序列的注释:我编写了代码来生成所需长度的非负数单调递增序列,然后插入 0 到 2 个(含)新元素,其值为int.MinValue or int.MaxValue(对于每次插入也是随机选择的)。通过这种方式,三分之一的测试涉及平凡有效的序列,第三个涉及需要找到要删除的正确单个元素的序列,第三个测试是无效的(即不满足可以使其单调递增的要求)最多删除一个元素)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

检查整数序列是否递增 的相关文章

  • WPF DataGrid 多选

    我读过几篇关于这个主题的文章 但很多都是来自 VS 或框架的早期版本 我想做的是从 dataGrid 中选择多行并将这些行返回到绑定的可观察集合中 我尝试创建一个属性 类型 并将其添加到可观察集合中 它适用于单个记录 但代码永远不会触发多个
  • 如何将 std::string& 转换为 C# 引用字符串

    我正在尝试将 C 函数转换为std string参考C 我的 API 如下所示 void GetStringDemo std string str 理想情况下 我希望在 C 中看到类似的东西 void GetStringDemoWrap r
  • 在模板类中声明模板友元类时出现编译器错误

    我一直在尝试实现我自己的链表类以用于教学目的 我在迭代器声明中指定了 List 类作为友元 但它似乎无法编译 这些是我使用过的 3 个类的接口 Node h define null Node
  • 没有特殊字符的密码验证器

    我是 RegEx 的新手 已经进行了大量搜索 但没有找到任何具体内容 我正在编写一个验证密码字符串的正则表达式 可接受的字符串必须至少具有 4 种字符类型中的 3 种 数字 小写字母 大写字母 特殊字符 我对包含有一个想法 也就是说 如果这
  • 根据属性的类型使用文本框或复选框

    如果我有这样的结构 public class Parent public string Name get set public List
  • 机器Epsilon精度差异

    我正在尝试计算 C 中双精度数和浮点数的机器 epsilon 值 作为学校作业的一部分 我在 Windows 7 64 位中使用 Cygwin 代码如下 include
  • 用于 FTP 的文件系统观察器

    我怎样才能实现FileSystemWatcherFTP 位置 在 C 中 这个想法是 每当 FTP 位置添加任何内容时 我都希望将其复制到我的本地计算机 任何想法都会有所帮助 这是我之前问题的后续使用 NET 进行选择性 FTP 下载 ht
  • 需要帮助优化算法 - 两百万以下所有素数的总和

    我正在尝试做一个欧拉计划 http projecteuler net问题 我正在寻找 2 000 000 以下所有素数的总和 这就是我所拥有的 int main int argc char argv unsigned long int su
  • 两个静态变量同名(两个不同的文件),并在任何其他文件中 extern 其中一个

    在一个文件中将变量声明为 static 并在另一个文件中进行 extern 声明 我认为这会在链接时出现错误 因为 extern 变量不会在任何对象中看到 因为在其他文件中声明的变量带有限定符 static 但不知何故 链接器 瑞萨 没有显
  • 如何定义一个可结构化绑定的对象的概念?

    我想定义一个concept可以检测类型是否T can be 结构化绑定 or not template
  • 为什么 C# 2.0 之后没有 ISO 或 ECMA 标准化?

    我已经开始学习 C 并正在寻找标准规范 但发现大于 2 0 的 C 版本并未由 ISO 或 ECMA 标准化 或者是我从 Wikipedia 收集到的 这有什么原因吗 因为编写 审查 验证 发布 处理反馈 修订 重新发布等复杂的规范文档需要
  • 如何在当前 Visual Studio 主机内的 Visual Studio 扩展中调试使用 Roslyn 编译的代码?

    我有一个 Visual Studio 扩展 它使用 Roslyn 获取当前打开的解决方案中的项目 编译它并从中运行方法 程序员可以修改该项目 我已从当前 VisualStudioWorkspace 成功编译了 Visual Studio 扩
  • 为什么使用小于 32 位的整数?

    我总是喜欢使用最小尺寸的变量 这样效果就很好 但是如果我使用短字节整数而不是整数 并且内存是 32 位字可寻址 这真的会给我带来好处吗 编译器是否会做一些事情来增强内存使用 对于局部变量 它可能没有多大意义 但是在具有数千甚至数百万项的结构
  • 如何在 Linq to SQL 中使用distinct 和 group by

    我正在尝试将以下 sql 转换为 Linq 2 SQL select groupId count distinct userId from processroundissueinstance group by groupId 这是我的代码
  • 相当于Linux中的导入库

    在 Windows C 中 当您想要链接 DLL 时 您必须提供导入库 但是在 GNU 构建系统中 当您想要链接 so 文件 相当于 dll 时 您就不需要链接 为什么是这样 是否有等效的 Windows 导入库 注意 我不会谈论在 Win
  • C# 中的 IPC 机制 - 用法和最佳实践

    不久前我在 Win32 代码中使用了 IPC 临界区 事件和信号量 NET环境下场景如何 是否有任何教程解释所有可用选项以及何时使用以及为什么 微软最近在IPC方面的东西是Windows 通信基础 http en wikipedia org
  • 使用特定参数从 SQL 数据库填充组合框

    我在使用参数从 sql server 获取特定值时遇到问题 任何人都可以解释一下为什么它在 winfom 上工作但在 wpf 上不起作用以及我如何修复它 我的代码 private void UpdateItems COMBOBOX1 Ite
  • 在OpenGL中,我可以在坐标(5, 5)处精确地绘制一个像素吗?

    我所说的 5 5 正是指第五行第五列 我发现使用屏幕坐标来绘制东西非常困难 OpenGL 中的所有坐标都是相对的 通常范围从 1 0 到 1 0 为什么阻止程序员使用屏幕坐标 窗口坐标如此严重 最简单的方法可能是通过以下方式设置投影以匹配渲
  • MySQL Connector C/C API - 使用特殊字符进行查询

    我是一个 C 程序 我有一个接受域名参数的函数 void db domains query char name 使用 mysql query 我测试数据库中是否存在域名 如果不是这种情况 我插入新域名 char query 400 spri
  • 指针和内存范围

    我已经用 C 语言编程有一段时间了 但对 C 语言还是很陌生 有时我对 C 处理内存的方式感到困惑 考虑以下有效的 C 代码片段 const char string void where is this pointer variable l

随机推荐