当前位置: 首页 > 知识库问答 >
问题:

最后剩下的号码

丘华翰
2023-03-14

我在一次采访中被问到这个问题。

给定正整数数组“arr”和数组的起始索引“k”。删除k处的元素,并以循环方式在数组中跳转arr[k]步。重复这样做,直到只剩下一个元素。找到最后剩下的元素。

我想到了使用有序映射的O(nlogn)解决方案。任何O(n)解都是可能的吗?

共有2个答案

令狐宣
2023-03-14

我想不出O(n)解决方案。但是,我们可以通过使用 treap 或增强的 BST 来获得 O(n log n) 平均时间,每个节点中都有一个值来表示其子树的大小。treap 使我们能够找到并删除 O(log n) 平均时间中的第 k个条目。

例如,A=[1,2,3,4]k=3(正如Sumit在评论中提醒我的那样,使用数组索引作为树中的值,因为它们是有序的):

          2(0.9)
         /     \
      1(0.81)   4(0.82)
               /
              3(0.76)

查找并删除第三个元素。从2开始,大小为2(包括左子树)。向右走。左子树的大小为1,加起来等于3,所以我们找到了第三个元素。删除:

          2(0.9)
         /     \
      1(0.81)   4(0.82)

现在,我们从数组中的第三个元素开始,其中 n - 1 = 3 个元素,并从那里查找第三个元素。我们将使用零索引来与我们的模算术相关联,因此模3中的第三个元素将是2和2 3 = 5 mod 3 = 2,第二个元素。我们立即找到它,因为带有左子树的根的大小为2。删除:

          4(0.82)
         /
      1(0.81)

现在我们从模数2中的第二个元素开始,所以1,我们加上2。3模2等于1。除去第一个元素,我们剩下4作为最后一个元素。

秦琦
2023-03-14

我的猜测是,这个问题没有< code>O(n)的解决方案,因为它似乎涉及到做一些不可能的事情。要在线性时间内解决这个问题,显然需要一个像数组这样的数据结构,它公开了对值的有序集合的两个操作:

    < li> O(1)按顺序从数据结构中删除。 在数据结构中查找第n个未删除的项目。

然而,这样的数据结构已经被正式证明是不存在的;参见“列表索引和子集排名的最佳算法”及其引用。说如果解决某个问题的自然方式涉及使用不可能的数据结构,问题本身很可能是不可能的,这并不是一个证明,但这样的直觉往往是正确的。

无论如何,在O(n log n)中有很多方法可以做到这一点。下面是在数组中维护未删除范围树的实现。下面的GetIndex()返回原始数组的索引,如果项目已被删除,则给定数组中从零开始的索引。这样的树不是自平衡的,因此在最坏的情况下会有O(n)操作,但在一般情况下DeleteGetIndex将是O(log n)

namespace CircleGame
{
    class Program
    {
        class ArrayDeletes
        {
            private class UndeletedRange
            {
                private int _size;
                private int _index;
                private UndeletedRange _left;
                private UndeletedRange _right;

                public UndeletedRange(int i, int sz)
                {
                    _index = i;
                    _size = sz;
                }

                public bool IsLeaf()
                {
                    return _left == null && _right == null;
                }

                public int Size()
                {
                    return _size;
                }

                public void Delete(int i)
                {
                    if (i >= _size)
                        throw new IndexOutOfRangeException();

                    if (! IsLeaf())
                    {
                        int left_range = _left._size;
                        if (i < left_range)
                            _left.Delete(i);
                        else
                            _right.Delete(i - left_range);
                        _size--;
                        return;
                    }

                    if (i == _size - 1)
                    {
                        _size--; // Can delete the last item in a range by decremnting its size
                        return;
                    }

                    if (i == 0)  // Can delete the first item in a range by incrementing the index
                    {  
                        _index++;
                        _size--;
                        return;
                    }

                    _left = new UndeletedRange(_index, i);
                    int right_index = i + 1;
                    _right = new UndeletedRange(_index + right_index, _size - right_index);
                    _size--;
                    _index = -1; // the index field of a non-leaf is no longer necessarily valid.
                }

                public int GetIndex(int i)
                {
                    if (i >= _size)
                        throw new IndexOutOfRangeException();

                    if (IsLeaf())
                        return _index + i;

                    int left_range = _left._size;
                    if (i < left_range)
                        return _left.GetIndex(i);
                    else
                        return _right.GetIndex(i - left_range);
                }

            }

            private UndeletedRange _root;

            public ArrayDeletes(int n)
            {
                _root = new UndeletedRange(0, n);
            }

            public void Delete(int i)
            {
                _root.Delete(i);
            }

            public int GetIndex(int indexRelativeToDeletes )
            {
                return _root.GetIndex(indexRelativeToDeletes);
            }

            public int Size()
            {
                return _root.Size();
            }
        }

        static int CircleGame( int[] array, int k )
        {
            var ary_deletes = new ArrayDeletes(array.Length);
            while (ary_deletes.Size() > 1)
            {
                int next_step = array[ary_deletes.GetIndex(k)];
                ary_deletes.Delete(k);
                k = (k + next_step - 1) % ary_deletes.Size();
            }
            return array[ary_deletes.GetIndex(0)];
        }

        static void Main(string[] args)
        {
            var array = new int[] { 5,4,3,2,1 };
            int last_remaining = CircleGame(array, 2); // third element, this call is zero-based...
        }
    }
}

另请注意,如果数组中的值已知有界,因此它们总是小于m小于n,则有许多O(nm)算法——例如,仅使用循环链表。

 类似资料:
  • 题目链接 NowCoder 题目描述 让小朋友们围成一个大圈。然后,随机指定一个数 m,让编号为 0 的小朋友开始报数。每次喊到 m-1 的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续 0...m-1 报数 .... 这样下去 .... 直到剩下最后一个小朋友,可以不用表演。 解题思路 约瑟夫环,圆圈长度为 n 的解可以看成长度为 n-1

  • 接下来的最短剩余时间如何解决这个问题?“最短作业优先”的抢占式版本。 我了解选择完成前剩余时间最少的过程来执行。但是,如果到达的新进程的突发时间与当前正在执行的进程的剩余完成时间完全相同,会发生什么情况? 如果一个新进程到达,其突发时间与当前执行的进程相同(如本例所示),那么当前执行的过程是否继续? 我的理解正确吗?提前谢谢你。

  • 问题内容: 我正在寻找后缀符号表示法的算法,该算法将产生最小数量的括号。 我发现它会产生很多括号:http : //tajendrasengar.blogspot.com/2011/09/postfix-to- infix-algorithm.html 例如 输入: 结果: 问题答案: 如果您确实希望尽可能地减少括号,则需要执行的操作与链接的算法类似。然而… 您应该为中的每个 复合 操作数存储一个

  • 如果已经读到了这里并且完成了所有的例子和练习,你现在对Vimscript基础的掌握就很牢固了。 不要担心,还有许多东西需要学呢! 如果你求知若渴,这里还有一些东西值得你去探索。 配色方案 在本书中我们给Potion文件添加了语法高亮。作为硬币的另一面,我们也可以创建配色方案来决定每种语法元素的颜色。 制作Vim的配色方案非常简单直白,甚至有点重复。阅读:help highlgiht来学习基础知识。

  • 问题内容: 有没有一种方法来获取数字的最后一位数字。我试图找到以“ 1”结尾的变量,例如1,11,21,31,41等。 如果我使用文本变量,我可以简单地输入 但是它适用于带有文本的变量(例如“ hello”),而不适用于数字。对于数字,我会遇到此错误: 我试图看看是否有更好的方法来处理数字。我知道一个解决方案是将其转换为字符串,然后执行上面的命令,但是我正在尝试查看是否还有另一种错过的方式。 提前

  • 我正在一个项目(简单的电话簿)为个人使用。我在删除listview(listView1)中的最后一个剩余项时遇到了麻烦。在这里你可以看看它是什么样子的: 所以,假设我在列表中有5个联系人,当我试图删除所有的联系人时,这是不可能的。只可能移除其中的4个。当我试图删除所有这些联系人,然后关闭/运行应用程序时,将不会有删除的联系人。当我试图删除其中4个并关闭/运行程序时,它们将被删除。当我试图删除最后一