容易的面试问题变得更加困难:给定数字1..100,在正好缺少k的情况下,找到缺失的数字

前一段时间我有一次有趣的面试经历。 这个问题开始很容易:

Q1:我们有一个包含数字的包123 ,..., 100 。 每个数字仅出现一次,因此有100个数字。 现在,从袋子中随机抽取一个号码。 查找丢失的号码。

我当然已经听过这个面试问题,所以我很快就回答了以下问题:

A1 :恩,数字1 + 2 + 3 + … + N的总和为(N+1)(N/2) (请参阅Wikipedia:算术级数之和 )。 对于N = 100 ,总和为5050

因此,如果袋子中所有数字都存在,则总和为5050 。 由于缺少一个数字,所以总和小于这个数字,而差就是那个数字。 因此我们可以找到O(N)时间和O(1)空间中的缺失数。

在这一点上,我认为我做得不错,但是突然之间,这个问题突然发生了变化:

Q2 :是的,但是现在如果缺少两个数字,您将如何处理?

我之前从未见过/听过/考虑过这种变化,所以我感到惊慌,无法回答这个问题。 面试官坚持要知道我的思维过程,所以我提到也许我们可以通过与预期产品进行比较来获得更多信息,或者也许在从第一遍收集到一些信息之后再进行第二遍,等等,但是我真的只是在拍摄在黑暗中,而不是真正找到解决方案的清晰途径。

面试官的确通过说第二个方程式确实是解决问题的一种方式来鼓励我。 在这一点上,我有点不高兴(因为事先不知道答案),并询问这是否是一种通用的(读作:“有用的”)编程技术,还是仅仅是一个技巧/陷阱。

面试官的回答让我感到惊讶:您可以推广该技术以找到3个缺失的数字。 实际上,您可以对其进行概括以找到k个缺失数字。

Qk :如果袋子中恰好缺少k个数字,您将如何有效地找到它?

这是几个月前,但我仍然不知道这种技术是什么。 显然,存在一个Ω(N)时间下限,因为我们必须至少扫描一次所有数字,但是访调员坚持认为,求解技术的TIMESPACE复杂度(减去O(N)时间输入扫描)定义为k不是N。

所以这里的问题很简单:

  • 您将如何解决Q2
  • 您将如何解决第3季度
  • 您将如何解决Qk

澄清说明

  • 通常,从1 .. N开始N个数字,而不仅仅是1..100。
  • 我不是在寻找明显的基于集合的解决方案,例如使用位集 ,通过指定位的值编码每个数字的存在/不存在,因此在其他空间中使用O(N)位。 我们无法承受与N成正比的任何额外空间。
  • 我也不在寻找明显的排序优先方法。 这种方法和基于集合的方法在采访中值得一提(它们易于实现,并且取决于N ,可能非常实用)。 我正在寻找“圣杯”解决方案(可能实现或可能不实际,但仍具有所需的渐近特性)。

同样,当然,您必须扫描O(N)的输入,但是您只能捕获少量信息(以k而不是N定义),然后必须以某种方式找到k个缺失的数字。


#1楼

我认为无需任何复杂的数学方程式和理论即可完成此操作。 以下是就地和O(2n)时间复杂度解决方案的建议:

输入表单假设:

袋中的数字数= n

缺失数字的数量= k

袋子中的数字由长度为n的数组表示

算法的输入数组的长度= n

数组中缺少的条目(从包装袋中取出的数字)将替换为数组中第一个元素的值。

例如。 最初的包看起来像[2,9,3,7,8,6,4,5,1,10]。 如果取出4,则4的值将变为2(数组的第一个元素)。 因此,在取出4个袋子之后,袋子看起来像[2,9,3,7,8,6,2,5,1,10]

该解决方案的关键是在遍历数组时,通过否定该索引的值来标记访问的数字的索引。

    IEnumerable<int> GetMissingNumbers(int[] arrayOfNumbers)
    {
        List<int> missingNumbers = new List<int>();
        int arrayLength = arrayOfNumbers.Length;

        //First Pass
        for (int i = 0; i < arrayLength; i++)
        {
            int index = Math.Abs(arrayOfNumbers[i]) - 1;
            if (index > -1)
            {
                arrayOfNumbers[index] = Math.Abs(arrayOfNumbers[index]) * -1; //Marking the visited indexes
            }
        }

        //Second Pass to get missing numbers
        for (int i = 0; i < arrayLength; i++)
        {                
            //If this index is unvisited, means this is a missing number
            if (arrayOfNumbers[i] > 0)
            {
                missingNumbers.Add(i + 1);
            }
        }

        return missingNumbers;
    }

#2楼

我请一个4岁的孩子解决这个问题。 他对数字进行了排序,然后进行了计数。 它的空间要求为O(厨房地板),并且工作原理很简单,但是缺少许多球。


#3楼

可能的解决方案:

public class MissingNumber {
    public static void main(String[] args) {
        // 0-20
        int [] a = {1,4,3,6,7,9,8,11,10,12,15,18,14};
        printMissingNumbers(a,20);
    }

    public static void printMissingNumbers(int [] a, int upperLimit){
        int b [] = new int[upperLimit];
        for(int i = 0; i < a.length; i++){
            b[a[i]] = 1;
        }
        for(int k = 0; k < upperLimit; k++){
            if(b[k] == 0)
                System.out.println(k);
        }
    }
}

#4楼

我认为可以这样概括:

将S,M表示为算术级数和乘法之和的初始值。

S = 1 + 2 + 3 + 4 + ... n=(n+1)*n/2
M = 1 * 2 * 3 * 4 * .... * n 

我应该考虑一个公式来计算,但这不是重点。 无论如何,如果缺少一个数字,则您已经提供了解决方案。 但是,如果缺少两个数字,则用S1和M1表示新的总和和总倍数,如下所示:

S1 = S - (a + b)....................(1)

Where a and b are the missing numbers.

M1 = M - (a * b)....................(2)

由于您知道S1,M1,M和S,因此上述方程式可求解来找到缺失的数字a和b。

现在,对于缺少的三个数字:

S2 = S - ( a + b + c)....................(1)

Where a and b are the missing numbers.

M2 = M - (a * b * c)....................(2)

现在您的未知数是3,而您只有两个方程式可以解决。


#5楼

这是一个使用k位额外存储的解决方案,没有任何巧妙的技巧,也很简单。 执行时间O(n),额外空间O(k)。 只是为了证明可以解决这一问题,而无需先阅读解决方案或成为天才:

void puzzle (int* data, int n, bool* extra, int k)
{
    // data contains n distinct numbers from 1 to n + k, extra provides
    // space for k extra bits. 

    // Rearrange the array so there are (even) even numbers at the start
    // and (odd) odd numbers at the end.
    int even = 0, odd = 0;
    while (even + odd < n)
    {
        if (data [even] % 2 == 0) ++even;
        else if (data [n - 1 - odd] % 2 == 1) ++odd;
        else { int tmp = data [even]; data [even] = dat
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值