📜  微软采访 |设置 26

📅  最后修改于: 2022-05-13 01:58:39.478000             🧑  作者: Mango

微软采访 |设置 26

第1轮:
关于以前工作的问题,以前工作中使用的设计模式。
给定两个以链表格式表示的整数,现在将这两个列表相加并将其放在第三个列表中,在任何时间点,一个节点都只能有一个数字。
随着讨论的出现,它就像考虑了结转,并且都类似于以链表方式表示的两个整数中的一些。面试要求先讲方法,再讲编码

// Approach 1
// 1 2 3
// 12 8 9
// 14 1 2 

版本 1:

Java
private static void Add(Node head1, Node head2)
{
    int res = 0;
    if (head1 != null)
    {
        count++;
        Add(head1.Next, head2.Next);
        count--;
        res = head1.Data + head2.Data + carryFwd;
        carryFwd = res / 10;
        Node newNumNode =null;
        newNumNode = new Node() { Data = res % 10 };
        if (head3 == null)
        {
            head3 = newNumNode;
        }
        else
        {
            newNumNode.Next = head3;
            head3 = newNumNode;
        }
    // happy with this logic where the list will go in
    // reverse direction something like Insert at the head
    // position every time a new node occurs to be created
}


Java
static int[] aa = new int[3];
    static int carryFwd = 0;
    static Node head3 = null;
    static int count;
    private static void Add(Node head1, Node head2)
    {
        int res = 0;
        if (head1 != null)
        {
            count++;
            Add(head1.Next, head2.Next);
            count--;
            res = head1.Data + head2.Data + carryFwd;
            carryFwd = res / 10;
            Node newNumNode =null;
            if (count == 0)
            {
                newNumNode = new Node() { Data = res };
            }
            else
            {
                newNumNode = new Node() { Data = res % 10 };
            }
            if (head3 == null)
            {
                head3 = newNumNode;
            }
            else
            {
                newNumNode.Next = head3;
                head3 = newNumNode;
            }
        }
    }
}


Java
private static void Add(Node head1, Node head2)
{
    int res = 0;
    if (head1 != null)
    {
        count++;
        Add(head1.Next, head2.Next);
        count--;
        res = head1.Data + head2.Data + carryFwd;
        carryFwd = res / 10;
        Node newNumNode =null;
        newNumNode = new Node() { Data = res % 10 };
        if (head3 == null)
        {
            head3 = newNumNode;
        }
        else
        {
            newNumNode.Next = head3;
            head3 = newNumNode;
        }
        if(carryFwd ==1)
        {
           newNumNode = new Node() { Data = carrFwd};
           newNumNode.Next = head3;
           head3 = newNumNode;
        }
    }


Java
public class Node
    {
        public int Data { get; set; }
        public Node Next { get; set; }
    }
}


C
int len = sizeof(arr)/sizeof(arr[0]);
int currMax = a[0], finalMax = arr[0];
for (int i=1;i<=len;i++) {
  currMax += a[i]; i
  if(currMax > finalMax)
      finalMax = currMax;
  if(currMax<0)
      currMax =0;
}


版本2:让我举个例子证明解决方案是正确的
如果最后一位数字也给出结转,我的一个测试用例失败

Java

static int[] aa = new int[3];
    static int carryFwd = 0;
    static Node head3 = null;
    static int count;
    private static void Add(Node head1, Node head2)
    {
        int res = 0;
        if (head1 != null)
        {
            count++;
            Add(head1.Next, head2.Next);
            count--;
            res = head1.Data + head2.Data + carryFwd;
            carryFwd = res / 10;
            Node newNumNode =null;
            if (count == 0)
            {
                newNumNode = new Node() { Data = res };
            }
            else
            {
                newNumNode = new Node() { Data = res % 10 };
            }
            if (head3 == null)
            {
                head3 = newNumNode;
            }
            else
            {
                newNumNode.Next = head3;
                head3 = newNumNode;
            }
        }
    }
}

版本 3:
这会将最后一位数字总和保存在单个节点中这不是我所期望的当总和为两位数时,所以请修复代码

Java

private static void Add(Node head1, Node head2)
{
    int res = 0;
    if (head1 != null)
    {
        count++;
        Add(head1.Next, head2.Next);
        count--;
        res = head1.Data + head2.Data + carryFwd;
        carryFwd = res / 10;
        Node newNumNode =null;
        newNumNode = new Node() { Data = res % 10 };
        if (head3 == null)
        {
            head3 = newNumNode;
        }
        else
        {
            newNumNode.Next = head3;
            head3 = newNumNode;
        }
        if(carryFwd ==1)
        {
           newNumNode = new Node() { Data = carrFwd};
           newNumNode.Next = head3;
           head3 = newNumNode;
        }
    }

版本 4:
您可以在这里进行更多优化吗...?两位数相加时的最大值是多少……?结转的可能值是什么……?背靠背问题
所以我的最终版本删除了 count 变量并将最后一个结转条件移到了函数之外。他在这里创造了更多的乐趣,这就是为什么他如此深入地挖掘。

Java

public class Node
    {
        public int Data { get; set; }
        public Node Next { get; set; }
    }
}

现在为这个问题编写测试用例。
大约 15 个测试用例意味着测试输入。我是通过查看我的解决方案来写的。
这里的问题是您是否为您的解决方案或问题编写测试用例,考虑这不是您的代码,您遇到问题并编写测试用例。
然后我忽略了我对列表长度相等的假设,添加了一些测试用例。
当我编写了一个链表大小为 10000000 的测试时,被要求写更多内容很高兴,因为我的解决方案是递归的,我可能会遇到堆栈溢出异常。
有了这个答案,他向我提出了很多问题。
面试官: 那你为什么选择递归?我需要一种替代方法,对替代方法不满意

// Approach 2
  /*
   * Reverse list 1:
   * Reverse list 2:
   * Add the lists with remainder and dividends
   * Reverse list 3:
  */

  // Approach 3
  /*
   * make the linked list to array and use the indices to 
     traverse and do the addition
   * No program is asked for it
  */

  // Approach 4
  /*
   * mConvert the entire linked list to an integer and then
     add both the integers and then prepare a linked list 
     with the result 
   * but the issue if the result is out of integer boundary
  */ 

当我告诉方法 4 他问我
采访者: “你是不是在想,为什么这家伙把整数存入链表,然后要求我添加这样的链表……?”
我:是的
面试官:那你自己回答一下是什么导致我这样,让我们交换角色
我:告诉了一些场景,比如
1.希望有基于索引的整数并动态增长(所以数组不会友好)
2. 如果我想要一个计数器的值大于整数范围,那么我可以使用这个或其他一些数据结构。
面试官:现在让我们再次回到这个问题,然后通过忽略您对列表长度相等的假设来修复您的代码
我:以上方法3和4都可以解决
采访者:但这些是替代方法来解决任何解决相同解决方案而不是使用替代方案的方法?
我:也许我会用零填充较小的列表,然后最初使用我的算法额外开销,但它有效。
面试官:好的,回到你的解决方案递归,当你有这么多的替代品时,你为什么跳起来开始使用递归……?
我:当有人在链表中提出问题时,我通常会想到递归,它有时会很容易解决,因为它是单向的。
采访者:你能详细说明递归如何简化开发者逻辑吗?
我:它使用内部树,通过它我可以在链表中执行反向操作
Vijj:它维护着什么树?
我:名字是一些 RecursionTree 但它实际上不是一棵树
采访者:那那是什么
我:一些数据结构
面试官:当然是什么数据结构
我:我希望它的堆栈能够以 LIFO 方式工作,这样我就可以轻松地进行反向操作。这就是为什么我的一个测试用例检查堆栈溢出异常的原因,因为我在拥有大量数据时使用递归。
采访者:什么是LIFO
我:解释了 LIFO 并与 FIFO 进行了比较。
采访者:有什么问题要问我……?
我:如果它不保密且不明显,请告诉我 Bing 使用的核心逻辑或算法是什么,正如我的经理所说,这是为 bing 团队准备的
面试官:好的,如果你想写一个搜索算法,你的方法是什么
我:我将使用一些基于启发式的搜索,例如最佳优先搜索类型的 A* 算法或 TSP(旅行销售人员)问题解决方案。
面试官:如果是这样的话,任何人都可以编写搜索引擎🙂我们也使用一些启发式方法,但永远不会像直接 A* 算法
还有一些关于 Google Vs Bing 的讨论,然后这都是我的观点,一旦我们与其他人交谈,你可能会成为 Bing 相关团队的一员。
第 2 轮:持续 1:30 分钟
面试官:会直接从问题开始,不会浪费时间。
给定一个由 +ves 和 -ves 组成的数组,在给定数组中任意长度的所有子数组中找到一个最大值为最大值的子数组。
先说方法再写代码
我:一段时间后,他告诉我 O(n) 复杂度的方法,然后他让我写代码

C

int len = sizeof(arr)/sizeof(arr[0]);
int currMax = a[0], finalMax = arr[0];
for (int i=1;i<=len;i++) {
  currMax += a[i]; i
  if(currMax > finalMax)
      finalMax = currMax;
  if(currMax<0)
      currMax =0;
}

面试官:取一些数字,证明你的解法是正确的
我:在示例中显示我需要遍历整个列表,直到我得到答案。
采访者:它在任何情况下都会失败吗?
我:没有,从来没有
面试官:如果数组中的所有数字都是-ves就会失败
我:但最初的问题是数组是 +ve 和 -ve 的混合
面试官:好的,那么让我换个问题,考虑一下它有所有 -ves,如果是这样,你的代码会在哪里失败?
我:是的,条件是 currMax
面试官:然后修复
我:花了很多时间修复然后让我证明正确性
我无法证明我的解决方案,因为我在跟踪大列表时丢失了某个地方,但解决方案是正确的,所以
面试官:他让我改变初始化和修复那个是提示
我:我无法解决,因为我坚持我的解决方案,但我提供了另一种方法,比如
我将所有 -ve 数字与 -1 相乘,并使列表充满 +ves ,然后找到子数组的最小值而不是最大值
面试官:很关心我写的函数的返回值是多少;他告诉你要使用替代解决方案而不是修复现有解决方案
采访者:好的,让我们去另一个问题,给定一棵树找到祖先
我:意思是父母、祖父母或祖父母
面试官:对你来说重要吗?你说祖父母的方法是什么
我:我说我可能会使用堆栈,根据您的选择,我会从堆栈中查看节点
采访者:好的,我们将讨论其他问题而不是这个。
面试官:我会在纸上画一棵树,然后给你花点时间记住数据结构中的树,一旦你说是,我会抹掉或收回我的论文,然后考虑数据结构是输入到你的算法和他们构造我的树回来
我:我无法理解这个问题问了太多他真正想要的问题,就像我将使用你的树构造树然后调用相同的函数来重新创建
面试官:你如何创建你的输入是什么数据结构是什么
我:我说Node blah blah ...问了太多问题然后我明白他想要什么
所以我的方法是我将在两个数组中表示你的树,一个是 Inorder,另一个是 pre/post 在这里我将使用 Pre,一旦我有了这两个数组,我可以通过给出这些输入来使用构造算法.
面试官:告诉我如果你这两个数组你怎么构造
我:我告诉结合这两个我们如何去构造像从 inorder 我们可以得到根元素并在第二个数组中找到那个根,然后将与树的左右相同的数组拆分为根并继续进行;这我需要为给定的树手动完成以证明我的解决方案;他在拆分子数组将去哪里以及如何记住左边和右边之后问了几个问题;手动我用例子解释了所有这些,我说当我把它写成程序时不知道需要检查什么条件
面试官:对这个方法很满意,问什么 In/Pre/Post oders 为什么你只选择这两个
我:我需要 Inorder,你可以告诉我你想让我拿前还是后
面试官:这取决于你,你的算法你的数据结构和编写程序
我:我无法将我的逻辑放入代码中,因为我无法以正常方式尝试适当的条件以及递归,但根本无法编写具体代码。
采访者:我们的时间不多了,所以就到此为止。
如果您喜欢 GeeksforGeeks 并愿意做出贡献,您还可以撰写文章并将您的文章邮寄至 review-team@geeksforgeeks.org。在 GeeksforGeeks 主页上查看您的文章并帮助其他 Geeks。

微软的所有练习题